/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  Eth.c
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL Eth plugins.
 */
#ifdef __cplusplus
extern "C" {
#endif


#include "Eth.h"
/* MODULE SELF USED */
#include "dwmac.h"
#include "EthBuff.h"
#include "EthDesc.h"
/* SOC TO DMA ADDRESS USED */
#include "Mcu_Soc.h"
#include "RegHelper.h"
/* CoreID USED */
// #include "Os.h"
#include "EthTrcv.h"
#include "EthIf.h"
#include "cdefs.h"
/* MODULE SELF USED */
#include "dwmac_common.h"
#include "Eth_Portable.h"
#include "Eth_Fault.h"
#include "Mcal_Cache.h"
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
#include "Dma.h"
#include "Eth_PBCfg.h"
#endif

/* Version and Check Begin */
/* Version Info Begin */
#define ETH_C_VENDOR_ID   0x8C
#define ETH_C_AR_RELEASE_MAJOR_VERSION    4
#define ETH_C_AR_RELEASE_MINOR_VERSION    3
#define ETH_C_AR_RELEASE_REVISION_VERSION 1
#define ETH_C_SW_MAJOR_VERSION    1
#define ETH_C_SW_MINOR_VERSION    0
#define ETH_C_SW_PATCH_VERSION    0
/* Version Info End */

/* Version Check Begin */
#if !defined(DISABLE_MCAL_ASR_VER_CHECK)
#if ((ETH_C_AR_RELEASE_MAJOR_VERSION != ETH_H_AR_RELEASE_MAJOR_VERSION)\
    || (ETH_C_AR_RELEASE_MINOR_VERSION != ETH_H_AR_RELEASE_MINOR_VERSION)\
    || (ETH_C_AR_RELEASE_REVISION_VERSION != ETH_H_AR_RELEASE_REVISION_VERSION))
#error "Opps, Eth.c and Eth.h AutoSAR version not match!"
#endif
#endif  /* !DISABLE_MCAL_ASR_VER_CHECK */
#if !defined(DISABLE_MCAL_SW_VER_CHECK)
#if ((ETH_C_SW_MAJOR_VERSION != ETH_H_SW_MAJOR_VERSION)\
    || (ETH_C_SW_MINOR_VERSION != ETH_H_SW_MINOR_VERSION)\
    || (ETH_C_SW_PATCH_VERSION != ETH_H_SW_PATCH_VERSION))
#error "Opps, Eth.c and Eth.h Software version not match!"
#endif
#endif  /* !DISABLE_MCAL_SW_VER_CHECK */

#define ETH_START_SEC_CONST_UNSPECIFIED
#include "Eth_MemMap.h"

// Define a constant static array of Eth_HardWare_Info_t type with 2 elements
const static Eth_HardWare_Info_t  HW_Info[2] = {
    // First element of the array
    {
        // Set the first element to the address of the ETH1_APB_REG_BASE
        (uint32)ETH1_APB_REG_BASE,
        // Set the second element to the index of the ETH1_SBD_INTR_IDX
        (uint32)ETH1_SBD_INTR_IDX

    },
    // Second element of the array
    {
        // Set the first element to the address of the ETH2_APB_REG_BASE
        (uint32)ETH2_APB_REG_BASE,
        // Set the second element to the index of the ETH2_SBD_INTR_IDX
        (uint32)ETH2_SBD_INTR_IDX
    }
};
/* mtl fifo size alloc tbl sum 10kbytes */
#define MTL_MEM_SIZE   MTL_QUEUE_SIZE

#define  FIFO_ALLOC_MUL(p) (((p)*(MTL_MEM_SIZE))/100)
/* mtl tx algorithm weights/quantum of DCB wfq mode tbl 0x3fff/16383 0 is 100%*/
#define  DCB_WFQ_WHT(p)    (10-(p))
/* tx queue memery proportion */
const static uint32  tx_queue_mem_tbl[5][5] = {
    {100, 0, 0, 0, 0},
    {40, 60, 0, 0, 0},
    {20, 30, 50, 0, 0},
    {10, 20, 30, 40, 0},
    {10, 10, 20, 30, 30}
};
/* default keep old mechanism */
#if !defined(ETH_NOT_RESET_DATABUFF)
#define ETH_NOT_RESET_DATABUFF  0
#endif /** #if !defined(ETH_NOT_RESET_DATABUFF) */

#define ETH_STOP_SEC_CONST_UNSPECIFIED
#include "Eth_MemMap.h"

#define ETH_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Eth_MemMap.h"
/*PRQA S 1751 70*/
VAR_ALIGN(Eth_Controller_t Eth_gCtrl_Eth0,CACHE_LINE);
#if ETH_MAXCTRLS_SUPPORTED == 2U
VAR_ALIGN(Eth_Controller_t Eth_gCtrl_Eth1,CACHE_LINE);
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */

#if STD_ON == ETH_GET_COUNTVAL_API
VAR_ALIGN(Eth_CounterType Eth_gCounter_Eth0,CACHE_LINE);
#if ETH_MAXCTRLS_SUPPORTED == 2U
VAR_ALIGN(Eth_CounterType Eth_gCounter_Eth1,CACHE_LINE);
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
#endif /* End of ETH_GET_COUNTVAL_API  */

#if STD_ON == ETH_GET_RXSTATS_API
VAR_ALIGN(Eth_RxStatsType Eth_gRxStats_Eth0,CACHE_LINE);
#if ETH_MAXCTRLS_SUPPORTED == 2U
VAR_ALIGN(Eth_RxStatsType Eth_gRxStats_Eth1,CACHE_LINE);
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
#endif /* End of ETH_GET_RXSTATS_API  */

#if STD_ON ==ETH_GET_TXSTATS_API
VAR_ALIGN(Eth_TxStatsType Eth_gTxStats_Eth0,CACHE_LINE);
#if ETH_MAXCTRLS_SUPPORTED == 2U
VAR_ALIGN(Eth_TxStatsType Eth_gTxStats_Eth1,CACHE_LINE);
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
#endif /* End of ETH_GET_TXSTATS_API */

#if STD_ON == ETH_GET_TXERRORCOUNT_API
VAR_ALIGN(Eth_TxErrorCounterValuesType Eth_gTxErrorCounter_Eth0,CACHE_LINE);
#if ETH_MAXCTRLS_SUPPORTED == 2U
VAR_ALIGN(Eth_TxErrorCounterValuesType Eth_gTxErrorCounter_Eth1,CACHE_LINE);
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
#endif /* End of ETH_GET_TXERRORCOUNT_API */

#define TX_TS_EN_BIT        (0x1u<<15u)
#define TX_DESC_IDX_MASK    (TX_TS_EN_BIT - 1u)
#define TX_DESC_IDX(idx)    (TX_DESC_IDX_MASK & (idx))

#define TX_DESC_CH_MASK     (0xFFFF0000u)
#define TX_DESC_CH_GEN(idx) (TX_DESC_CH_MASK & ((uint32)(idx) << 16U))
#define TX_DESC_CH_GET(idx) ((uint8)((TX_DESC_CH_MASK & ((uint32)(idx))) >> 16u))

#if (STD_ON == ETH_GET_GLOBALTIME_API || ETH_MAX_DMA_CHANNEL > 1)

VAR_ALIGN(uint32 Eth_gTxTimeStamp0[CTRL0_TX_BUFF_COUNT],CACHE_LINE);
VAR_ALIGN(uint32 Eth_gRxTimeStamp0[CTRL0_RX_BUFF_COUNT],CACHE_LINE);
#if ETH_MAXCTRLS_SUPPORTED == 2U
VAR_ALIGN(uint32 Eth_gTxTimeStamp1[CTRL1_TX_BUFF_COUNT],CACHE_LINE);
VAR_ALIGN(uint32 Eth_gRxTimeStamp1[CTRL1_RX_BUFF_COUNT],CACHE_LINE);
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */

#endif /* End of (STD_ON == ETH_GET_GLOBALTIME_API || ETH_MAX_DMA_CHANNEL > 1) */

#if ETH_MAX_DMA_CHANNEL > 1
VAR_ALIGN(uint8 Eth_gTxPrioty0[CTRL0_TX_BUFF_COUNT],CACHE_LINE);
#if ETH_MAXCTRLS_SUPPORTED == 2U
VAR_ALIGN(uint8 Eth_gTxPrioty1[CTRL1_TX_BUFF_COUNT],CACHE_LINE);
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
#endif /* End of ETH_MAX_DMA_CHANNEL > 1 */

#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
static const Eth_DrctFwdConfigType *Eth_FwdCfg;

static struct dma_desc *ethDma_tx_tail_desc[ETH_DIRECT_FORWARD_NUM];
static struct dma_desc *ethDma_rx_tail_desc[ETH_DIRECT_FORWARD_NUM];
static uint32 *ethDma_opd2_data[ETH_DIRECT_FORWARD_NUM][MAX_ETH_RING_LENTH];
#endif

#define ETH_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

#define ETH_START_SEC_VAR_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

VAR(Eth_Controller_t*, ETH_VAR)   Eth_gCtrl[ETH_MAXCTRLS_SUPPORTED] = {
    &Eth_gCtrl_Eth0,
#if ETH_MAXCTRLS_SUPPORTED == 2U
    &Eth_gCtrl_Eth1
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
};

#if STD_ON == ETH_GET_COUNTVAL_API
// Declare a variable of type Eth_CounterType* and name it ETH_VAR
VAR(Eth_CounterType*, ETH_VAR)   Eth_gCounter[ETH_MAXCTRLS_SUPPORTED]={
    // Initialize the first element of the array with the address of Eth_gCounter_Eth0
    &Eth_gCounter_Eth0,
#if ETH_MAXCTRLS_SUPPORTED == 2U
    // If the maximum number of supported controllers is 2, initialize the second
    //element of the array with the address of Eth_gCounter_Eth1
    &Eth_gCounter_Eth1
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
};
#endif /* End of ETH_GET_COUNTVAL_API  */

#if STD_ON == ETH_GET_RXSTATS_API
// Declare a variable of type Eth_RxStatsType* and name it ETH_VAR
VAR(Eth_RxStatsType*, ETH_VAR)    Eth_gRxStats[ETH_MAXCTRLS_SUPPORTED] = {
    // Assign the address of Eth_gRxStats_Eth0 to the first element of the array
    &Eth_gRxStats_Eth0,
#if ETH_MAXCTRLS_SUPPORTED == 2U
    // If the maximum number of supported controllers is 2, assign the address of
    //Eth_gRxStats_Eth1 to the second element of the array
    &Eth_gRxStats_Eth1
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
};
#endif /* End of ETH_GET_RXSTATS_API  */

#if STD_ON ==ETH_GET_TXSTATS_API
// Declare a variable of type Eth_TxStatsType* and name it ETH_VAR
VAR(Eth_TxStatsType*, ETH_VAR)    Eth_gTxStats[ETH_MAXCTRLS_SUPPORTED] = {
    // Assign the address of Eth_gTxStats_Eth0 to the first element of the array
    &Eth_gTxStats_Eth0,
#if ETH_MAXCTRLS_SUPPORTED == 2U
    // If the maximum number of supported controllers is 2, assign the address of
    // Eth_gTxStats_Eth1 to the second element of the array
    &Eth_gTxStats_Eth1
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
};
#endif /* End of ETH_GET_TXSTATS_API */

#if STD_ON == ETH_GET_TXERRORCOUNT_API
// Declare a variable of type Eth_TxErrorCounterValuesType* and assign it to the ETH_VAR macro
VAR(Eth_TxErrorCounterValuesType*, ETH_VAR)   Eth_gTxErrorCounter[ETH_MAXCTRLS_SUPPORTED]={
    // Assign the address of Eth_gTxErrorCounter_Eth0 to the first element of the array
    &Eth_gTxErrorCounter_Eth0,
#if ETH_MAXCTRLS_SUPPORTED == 2U
    // If the maximum number of supported controllers is 2, assign the address of
    //Eth_gTxErrorCounter_Eth1 to the second element of the array
    &Eth_gTxErrorCounter_Eth1
#endif /* End of ETH_MAXCTRLS_SUPPORTED ==2 */
};
#endif /* End of ETH_GET_TXERRORCOUNT_API */

#if (STD_ON == ETH_GET_GLOBALTIME_API || ETH_MAX_DMA_CHANNEL > 1)

// Declare an array of uint32 variables with automatic storage duration and the name Eth_gTxTimeStamp
P2VAR(uint32, AUTOMATIC, ETH_VAR) Eth_gTxTimeStamp[ETH_MAXCTRLS_SUPPORTED] = {
    // Initialize the first element of the array with the value of Eth_gTxTimeStamp0
    Eth_gTxTimeStamp0,
    // If the maximum number of supported controls is 2, initialize the second
    //element of the array with the value of Eth_gTxTimeStamp1
#if ETH_MAXCTRLS_SUPPORTED == 2U
    Eth_gTxTimeStamp1,
#endif
};

// Declare an array of uint32 variables with automatic storage duration and the name Eth_gRxTimeStamp
P2VAR(uint32, AUTOMATIC, ETH_VAR) Eth_gRxTimeStamp[ETH_MAXCTRLS_SUPPORTED] = {
    // Initialize the first element of the array with the value of Eth_gRxTimeStamp0
    Eth_gRxTimeStamp0,
    // If the maximum number of supported controls is 2, initialize the second element of
    //the array with the value of Eth_gRxTimeStamp1
#if ETH_MAXCTRLS_SUPPORTED == 2U
    Eth_gRxTimeStamp1,
#endif
};
#endif

#if ETH_MAX_DMA_CHANNEL > 1

// Define an array of uint8 type variables with automatic storage duration and the name Eth_gTxPriorty
P2VAR(uint8, AUTOMATIC, ETH_VAR) Eth_gTxPriorty[ETH_MAXCTRLS_SUPPORTED] = {
    // Initialize the first element of the array with the value of Eth_gTxPrioty0
    Eth_gTxPrioty0,
    // If the maximum number of supported controllers is 2, initialize the
    //second element of the array with the value of Eth_gTxPrioty1
#if ETH_MAXCTRLS_SUPPORTED == 2U
    Eth_gTxPrioty1,
#endif
};


#endif

#define ETH_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE
#include "Eth_MemMap.h"

#if STD_ON == ETH_GET_GLOBALTIME_API
/**
 * @brief Retrieves the DMA descriptor based on control and buffer indices.
 *
 * This function returns a pointer to the DMA descriptor corresponding to the
 * given control index and buffer index.
 *
 * @param CtrlIdx The control index.
 * @param BufIdx The buffer index.
 *
 * @return A pointer to the DMA descriptor.
 */
static struct dma_desc *form_bufidx_get_desc(uint8 CtrlIdx, uint32 BufIdx)
{
    return &Eth_Desc_Buf[CtrlIdx][TX_DESC_CH_GET(Eth_gTxTimeStamp[CtrlIdx][BufIdx])][DESC_TX].
           desc[TX_DESC_IDX(Eth_gTxTimeStamp[CtrlIdx][BufIdx])];
}
/* this api for debug & test only */
/**
 * @brief Parses a string and returns an integer.
 * Parses a given string and converts it into an integer value.
 *
 * @param str The string to be parsed.
 * @return An integer representing the parsed value, or 0 if the input is invalid.
 */
uint8 form_bufidx_get_desc_chan(uint8 CtrlIdx, uint16 BufIdx)
{
    return TX_DESC_CH_GET(Eth_gTxTimeStamp[CtrlIdx][BufIdx]);
}
#endif

/**
 * @brief Updates the MMC (Media Management Counters) status for a given
 * Ethernet controller.
 *
 * This function updates the receive and transmit statistics, counters, and
 * transmit error counts for the specified Ethernet controller index.
 * It decides whether to update each type of MMC status based on the
 * compilation flags (STD_ON defines).
 *
 * @param CtrlIdx The index of the Ethernet controller whose MMC status is to be updated.
 */
FUNC(void, ETH_CODE)  Eth_update_mmc_status(VAR(uint8, AUTOMATIC) CtrlIdx)
{
#if STD_ON == ETH_GET_RXSTATS_API
    // Update receive statistics if the RXSTATS API is enabled
    rx_stats_update(ETH_CFG_CTRL_REG_BASE(CtrlIdx), Eth_gRxStats[CtrlIdx]);
#else
    // If RXSTATS API is disabled, call the function with a NULL pointer
    rx_stats_update(ETH_CFG_CTRL_REG_BASE(CtrlIdx), NULL_PTR);
#endif
#if STD_ON ==ETH_GET_TXSTATS_API
    // Update transmit statistics if the TXSTATS API is enabled
    tx_stats_update(ETH_CFG_CTRL_REG_BASE(CtrlIdx), Eth_gTxStats[CtrlIdx]);
#else
    // If TXSTATS API is disabled, call the function with a NULL pointer
    tx_stats_update(ETH_CFG_CTRL_REG_BASE(CtrlIdx), NULL_PTR);
#endif
#if STD_ON == ETH_GET_COUNTVAL_API
    // Update controller counters if the COUNTVAL API is enabled
    controller_counter_update(ETH_CFG_CTRL_REG_BASE(CtrlIdx), Eth_gCounter[CtrlIdx]);
#else
    // If COUNTVAL API is disabled, call the function with a NULL pointer
    controller_counter_update(ETH_CFG_CTRL_REG_BASE(CtrlIdx), NULL_PTR);
#endif
#if STD_ON == ETH_GET_TXERRORCOUNT_API
    // Update transmit error counts if the TXERRORCOUNT API is enabled
    tx_error_count_update(ETH_CFG_CTRL_REG_BASE(CtrlIdx), Eth_gTxErrorCounter[CtrlIdx]);
#else
    // If TXERRORCOUNT API is disabled, call the function with a NULL pointer
    tx_error_count_update(ETH_CFG_CTRL_REG_BASE(CtrlIdx), NULL_PTR);
#endif
}

/**
 * @brief Initializes the MMC (Media Management Counter) status variables for the specified Ethernet controller.
 *
 * This function initializes the MMC status variables (e.g., receive and transmit statistics, counters,
 * and error counters) for the specified Ethernet controller. It clears the relevant status variables
 * based on the configuration macros defined in the project (e.g., `ETH_GET_RXSTATS_API`, `ETH_GET_TXSTATS_API`,
 * `ETH_GET_COUNTVAL_API`, and `ETH_GET_TXERRORCOUNT_API`).
 *
 * @param CtrlIdx The index of the Ethernet controller for which to initialize the MMC status variables.
 *
 * @note The function assumes that the relevant MMC status variables (`Eth_gRxStats`, `Eth_gTxStats`,
 *       `Eth_gCounter`, and `Eth_gTxErrorCounter`) are allocated and accessible for the specified
 *       Ethernet controller index.
 *
 * @note The function uses `Mcal_MemSet` to clear the MMC status variables, ensuring that all counters and
 *       statistics are reset to zero.
 *
 * @warning The caller must ensure that the `CtrlIdx` parameter is valid and corresponds to an
 *          initialized Ethernet controller.
 *
 * @warning The function does not perform any checks on the availability or validity of the MMC status
 *          variables; it assumes that they are properly allocated and accessible.
 */
static void Eth_Init_mmc_status(uint8 CtrlIdx)
{
#if STD_ON == ETH_GET_RXSTATS_API
    Mcal_MemSet(Eth_gRxStats[CtrlIdx],0,sizeof(Eth_RxStatsType));
#endif
#if STD_ON ==ETH_GET_TXSTATS_API
    Mcal_MemSet(Eth_gTxStats[CtrlIdx],0,sizeof(Eth_TxStatsType));
#endif
#if STD_ON == ETH_GET_COUNTVAL_API
    Mcal_MemSet(Eth_gCounter[CtrlIdx],0,sizeof(Eth_CounterType));
#endif
#if STD_ON == ETH_GET_TXERRORCOUNT_API
    Mcal_MemSet(Eth_gTxErrorCounter[CtrlIdx],0,sizeof(Eth_TxErrorCounterValuesType));
#endif
}

#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE_FAST
#include "Eth_MemMap.h"

#if STD_ON == ETH_DEV_ERROR_DETECT
/**
 * @brief Checks if the specified Ethernet controller can be accessed by the given core.
 *
 * This function checks whether the specified Ethernet controller can be accessed by the given core
 * based on the configuration stored in the `Eth_Control_Config` structure. It iterates through the
 * configuration of the given core to find the specified Ethernet controller index.
 *
 * @param EthCrtlIdx The index of the Ethernet controller to check.
 * @param Core The index of the core to check for access to the specified Ethernet controller.
 *
 * @return `E_OK` if the specified Ethernet controller can be accessed by the given core, or
 *         `E_NOT_OK` if the controller cannot be accessed or if the configuration for the given core
 *         is not available.
 *
 * @note The function assumes that the `Eth_Control_Config` structure is initialized and contains
 *       valid configuration data for the Ethernet controllers and cores.
 *
 * @warning The caller must ensure that the `EthCrtlIdx` and `Core` parameters are valid and
 *          correspond to initialized Ethernet controllers and cores.
 *
 * @warning The function does not perform any dynamic checks on the availability or state of the
 *          Ethernet controllers or cores; it relies solely on the configuration data stored in
 *          `Eth_Control_Config`.
 */
/*PRQA S 1557,1559 20*/
LOCAL_INLINE FUNC(Std_ReturnType, ETH_CODE) Eth_CheckCurCoreCanAccess(uint8 EthCrtlIdx, uint8 Core)
{
    uint8 Ctrl;
    Std_ReturnType RetVal = E_OK;

    if (NULL_PTR != Eth_Control_Config.EthCoreConfig[Core]) {
        for (Ctrl = 0 ; Ctrl < Eth_Control_Config.EthCoreConfig[Core]->EthMaxControllers; Ctrl++) {
            if (Eth_Control_Config.EthCoreConfig[Core]->EthCntrlConfigPtr[Ctrl].EthCtrlIdx == EthCrtlIdx)
                break;
        }

        if (Eth_Control_Config.EthCoreConfig[Core]->EthMaxControllers <= Ctrl) {
            RetVal = E_NOT_OK;
        }
    } else {
        RetVal = E_NOT_OK;
    }

    return RetVal;
}
#endif
/**
 * @brief Allocates and initializes a DMA descriptor for Ethernet operations.
 *
 * This function allocates a DMA descriptor for the specified Ethernet controller,
 * channel, and direction (receive or transmit). It initializes the descriptor
 * according to the provided parameters, including the data pointer, length, and flags.
 *
 * @param CtrlIdx The index of the Ethernet controller.
 * @param Channel The channel on which the DMA operation will take place.
 * @param dir_rx Boolean indicating the direction of the DMA operation (true for
 *               receive, false for transmit).
 * @param len The length of the data buffer pointed to by `dataptr`.
 * @param dataptr The pointer to the data buffer to be used by the DMA operation.
 * @param flags Flags used to configure the DMA descriptor for the operation.
 *
 * @return Pointer to the allocated and initialized DMA descriptor, or NULL_PTR
 * if allocation fails or the address is unaligned.
 *
 * @note This function assumes that the `alloc_dma_desc` function is responsible
 * for allocating a DMA descriptor that meets the alignment requirements.
 *       It also assumes that the `soc_to_dma_address` function converts a system
 * memory address to a DMA-accessible address.
 */
LOCAL_INLINE FUNC(struct dma_desc *, ETH_CODE) Eth_AllocDesc
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint8, AUTOMATIC) Channel,
    VAR(boolean, AUTOMATIC) dir_rx,
    VAR(uint32, AUTOMATIC) len,
    VAR(uint32, AUTOMATIC) dataptr,
    VAR(uint32, AUTOMATIC) flags
)
{

    P2VAR(struct dma_desc, AUTOMATIC, AUTOMATIC) tdesc;

    tdesc = alloc_dma_desc(CtrlIdx, Channel, dir_rx);

    /* Error Inject Point */
    EthFaultInj_Eth_AllocDesc_Invalide();

    if (((uint32)tdesc & 0x1F) || (NULL_PTR == tdesc)) {
        /* Unalign error or alloc fail */
        return NULL_PTR;
    }

    /*swap to dma address */
    dataptr = soc_to_dma_address(dataptr);

    if (dir_rx) {
        dwmac_clear(tdesc);
        dwmac_set_addr(tdesc, (uint32 *)dataptr);
        dwmac_rd_init_rx_desc(tdesc, ETH_CFG_CTRL_RX_INT_MODE(CtrlIdx));
    } else {
        dwmac_rd_init_tx_desc(tdesc);
        dwmac_set_addr(tdesc, (uint32 *)dataptr);
        dwmac_rd_prepare_tx_desc(tdesc, len, len, flags);
    }

    return tdesc;

}

/**
 * @brief Re-initializes a receive DMA descriptor for an Ethernet controller.
 *
 * This function re-initializes a receive DMA descriptor that has been previously
 * allocated and locked for an Ethernet controller. It sets the DMA address of the
 * receive buffer, initializes the DMA descriptor for receive operations, and updates
 * any necessary status flags or timestamps.
 *
 * @param CtrlIdx The index of the Ethernet controller for which the DMA
 *                descriptor is being re-initialized.
 * @param locked_desc Pointer to a `locked_desc_t` structure that contains
 *                    the locked DMA descriptor and related information.
 *
 * @note This function assumes that the `locked_desc` structure has already been
 * allocated, locked, and its `desc` field points to a valid DMA descriptor.
 *       It also assumes that the `EthBuffAddr` function returns the CPU address
 *       of the receive buffer, which is then converted to a DMA-accessible address.
 *       The function handles cache coherency if necessary (based on compile-time
 *       configuration).
 *       Additionally, it updates a global timestamp array (if enabled) with
 *       the receive descriptor's index.
 */
FUNC(void, ETH_CODE) Eth_ReInitRxDesc
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint8, AUTOMATIC) Channel,
    P2VAR(locked_desc_t, AUTOMATIC, AUTOMATIC) locked_desc
)
{
    P2VAR(uint8, AUTOMATIC, AUTOMATIC) Mem;
    P2VAR(struct dma_desc, AUTOMATIC, AUTOMATIC) tdesc = (struct dma_desc *)locked_desc->desc;

    Mem = (uint8 *)EthBuffAddr(CtrlIdx, locked_desc->buf_idx, TRUE);

    /* The address saved here is the CPU address */
    locked_desc->confirm = LOCKED_DESC_RX_DMA;

    dwmac_clear(tdesc);
    dwmac_set_addr(tdesc, (uint32 *)soc_to_dma_address((uint32)Mem));
    dwmac_rd_init_rx_desc(tdesc, ETH_CFG_CTRL_RX_INT_MODE(CtrlIdx));
#if (ETH_NO_CACHEABLE_NEEDED == STD_OFF)
    /*PRQA S 0326 2*/
    Mcal_FlushCache((uint32)tdesc, ROUNDUP(sizeof(struct dma_desc), CACHE_LINE));
#endif
    if (locked_desc_put(CtrlIdx, Channel, locked_desc, TRUE) < 0) {
        /* impossible to run to this position, QAC do this check */
    }

#if STD_ON == ETH_GET_GLOBALTIME_API
    Eth_gRxTimeStamp[CtrlIdx][locked_desc->buf_idx] = GET_RX_DESC_INDEX(CtrlIdx, MULTI_CH_RX_CH_IDX,
            tdesc);
#endif
}

#define ETH_STOP_SEC_CODE_FAST
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE
#include "Eth_MemMap.h"

/**
 * @brief Initializes the receive ring for an Ethernet controller and channel.
 *
 * This function initializes the receive ring by allocating buffers, initializing DMA descriptors,
 * and placing them into the receive queue for the specified Ethernet controller and channel.
 * It ensures that each buffer and descriptor pair is correctly configured for receive operations.
 *
 * @param CtrlIdx The index of the Ethernet controller for which the receive ring is being initialized.
 * @param Channel The channel on which the receive ring will operate.
 *
 * @return Std_ReturnType indicating the success or failure of the initialization process.
 *         Returns E_OK on success, E_NOT_OK if an error occurs during buffer allocation or descriptor initialization.
 *
 * @note This function assumes that the `EthBuffAlloc` function is responsible for allocating receive buffers,
 *       and the `Eth_AllocDesc` function is responsible for allocating and initializing DMA descriptors.
 *       It also handles cache coherency if necessary (based on compile-time configuration) and updates
 *       a global timestamp array (if enabled) with the receive descriptor's index.
 *       Finally, it sets the tail pointer of the receive ring to the last initialized DMA descriptor.
 */
LOCAL_INLINE FUNC(Std_ReturnType, ETH_CODE) Init_Recive_Ring
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint8, AUTOMATIC) Channel
)
{
    // Declare variables
    VAR(uint16, AUTOMATIC) len;
    VAR(sint32, AUTOMATIC) ret;
    VAR(uint32, AUTOMATIC) count;
    VAR(locked_desc_t, AUTOMATIC) fream;
    P2VAR(struct dma_desc, AUTOMATIC, AUTOMATIC) tdesc;
    P2VAR(uint8, AUTOMATIC, AUTOMATIC) Mem;
    VAR(Eth_BufIdxType, AUTOMATIC) BufIdx;

    // Loop through the ring
    for (count = 0; count < MAX_ETH_RING_LENTH; count++) {
        // Get the MTU length
        len = ETH_CFG_CTRL_MTU(CtrlIdx);
        // Allocate a buffer
        ret = EthBuffAlloc(CtrlIdx, &len, &Mem, &BufIdx, TRUE);
        /* Error Inject Point */
        EthFaultInj_Eth_RxBuffer_Invalide();
        // Check if the buffer was allocated successfully
        if ((ret < 0) || (Mem == NULL_PTR)) {
            return E_NOT_OK;
        }

        // Allocate a descriptor
        tdesc = Eth_AllocDesc(CtrlIdx, Channel, TRUE, len, (uint32)Mem, 0);

        // Check if the descriptor was allocated successfully
        if (tdesc == NULL_PTR) {
            return E_NOT_OK;
        }

        // Save the address of the descriptor
        fream.desc = (VAR(uint32, AUTOMATIC))tdesc;
        fream.buf_idx = BufIdx;
        fream.confirm = LOCKED_DESC_RX_DMA;
#if (ETH_NO_CACHEABLE_NEEDED == STD_OFF)
        /*PRQA S 0326 2*/
        Mcal_FlushCache((uint32)tdesc, ROUNDUP(sizeof(struct dma_desc), CACHE_LINE));
#endif
        if (locked_desc_put(CtrlIdx, Channel, &fream, TRUE ) < 0) {
            /* Impossible to run to this position, QAC do this check */
        }

#if STD_ON == ETH_GET_GLOBALTIME_API
        // Save the timestamp
        Eth_gRxTimeStamp[CtrlIdx][BufIdx] = GET_RX_DESC_INDEX(CtrlIdx, Channel, tdesc);
#endif
    }

    // Set the ring tail pointer
    dwmac_set_rx_tail_ptr(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                          soc_to_dma_address(((uint32)tdesc + sizeof(struct dma_desc))), \
                          Channel);

    return E_OK;
}

/**
 * @brief Initializes the control data structure for an Ethernet controller.
 *
 * This function initializes the control data structure associated with an Ethernet controller
 * by setting various configuration parameters and resetting internal counters.
 *
 * @param Idx A dummy parameter that is not currently used by the function.
 * @param CfgPtr Pointer to an `Eth_CntrlConfigType` structure containing the configuration
 *               parameters for the Ethernet controller.
 *
 * @return uint8 The index of the initialized Ethernet controller.
 *
 * @note The `Idx` parameter is included in the function signature but is not used within the function body.
 *       It might be intended for future use or as a placeholder for compatibility with other functions.
 *       The function sets up the controller's control data structure (`Eth_gCtrl[CtrlIdx]`) with information
 *       such as the configuration pointer, controller mode, state, register base address, IRQ number,
 *       and various counters.
 */
LOCAL_INLINE FUNC(uint8, ETH_CODE) Eth_Init_CtrlData
(
    VAR(uint8, AUTOMATIC) Idx,
    P2CONST(Eth_CntrlConfigType, AUTOMATIC, ETH_APPL_CONST) CfgPtr
)
{
    // Get the SoC index based on the Ethernet controller index
    uint32 SocIdx = ((CfgPtr->SocCtrlIdx == (uint32)ETH1) ? 0 : 1);

    // Get the Ethernet controller index
    uint8 CtrlIdx = CfgPtr->EthCtrlIdx;

    // Initialize the Ethernet controller structure
    Eth_gCtrl[CtrlIdx]->Init_Param = CfgPtr;
    Eth_gCtrl[CtrlIdx]->Controler_Mode = ETH_MODE_DOWN;
    Eth_gCtrl[CtrlIdx]->Controler_State = ETH_STATE_UNINIT;
    Eth_gCtrl[CtrlIdx]->RegBase = (uint32)(HW_Info[SocIdx].RegBase);
    Eth_gCtrl[CtrlIdx]->CtrlIdx = CtrlIdx;
    Eth_gCtrl[CtrlIdx]->IrqNum = (uint32)(HW_Info[SocIdx].IrqNum);
    Eth_gCtrl[CtrlIdx]->LastCur = 0;
    Eth_gCtrl[CtrlIdx]->RetryCnt = 0;
    Eth_gCtrl[CtrlIdx]->ReinitCnt = 0;

#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
    const Eth_DrctFwdConfigType *FwdCfg = Eth_FwdCfg;
    uint32 i = 0;

    for (i = 0; i < ETH_DIRECT_FORWARD_NUM; i++) {
        if (0 == CtrlIdx) {
            if (ETH1ToETH2 == FwdCfg[i].direction) {
                Eth_gCtrl[CtrlIdx]->EnableRxDrctQue = TRUE;
                Eth_gCtrl[CtrlIdx]->macSrcFilterEn  = FwdCfg[i].macSrcFilterEn;
                Eth_gCtrl[CtrlIdx]->EnableBcDup     = FwdCfg[i].bcDupEn;
            }
            else {
                Eth_gCtrl[CtrlIdx]->EnableTxDrctQue = TRUE;
            }
        }
        else
        {
            if (ETH2ToETH1 == FwdCfg[i].direction) {
                Eth_gCtrl[CtrlIdx]->EnableRxDrctQue = TRUE;
                Eth_gCtrl[CtrlIdx]->macSrcFilterEn  = FwdCfg[i].macSrcFilterEn;
                Eth_gCtrl[CtrlIdx]->EnableBcDup     = FwdCfg[i].bcDupEn;
            }
            else {
                Eth_gCtrl[CtrlIdx]->EnableTxDrctQue = TRUE;
            }
        }
    }
#endif
    // Return the Ethernet controller index
    return CtrlIdx;
}

/**
 * @brief Performs an access test for an Ethernet controller's registers.
 *
 * This function checks if the registers of the specified Ethernet controller are accessible
 * by performing a simple read operation. It is typically used for diagnostic purposes or
 * to ensure that the controller's registers are properly mapped in memory.
 *
 * @param CtrlIdx The index of the Ethernet controller to test.
 *
 * @return boolean TRUE if the registers are accessible, FALSE otherwise.
 *
 * @note The function uses the `dwmac_access_test` function to perform the actual register access test.
 *       It assumes that the `ETH_CFG_CTRL_REG_BASE` macro returns the base register address of the
 *       specified Ethernet controller.
 */
static FUNC(boolean, ETH_CODE) Eth_Access_Test
(
    VAR(uint8, AUTOMATIC) CtrlIdx
)
{
    return dwmac_access_test(ETH_CFG_CTRL_REG_BASE(CtrlIdx));
}

/**
 * @brief Initializes the DMA for an Ethernet controller, including its channels and rings.
 *
 * This function initializes the DMA controller for an Ethernet controller, including setting up
 * the DMA channels, configuring the receive and transmit rings, and enabling DMA interrupts.
 *
 * @param CtrlIdx The index of the Ethernet controller for which the DMA is being initialized.
 * @param Rx_irq Boolean indicating whether to enable receive interrupts for the DMA channels.
 * @param Tx_irq Boolean indicating whether to enable transmit interrupts for the DMA channels.
 *
 * @note This function iterates over all DMA channels (up to `ETH_MAX_DMA_CHANNEL`), initializing
 *       each channel's DMA control registers, setting the receive and transmit ring lengths,
 *       initializing the ring base addresses, configuring the receive buffer size, and enabling
 *       DMA interrupts based on the `Rx_irq` and `Tx_irq` parameters.
 *
 *       It assumes that the `Eth_Desc_Buf` array has been properly initialized with DMA descriptor
 *       buffers for each channel and direction (receive and transmit).
 */
FUNC(void, ETH_CODE) Eth_Ctrl_Init_DMA
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(boolean, AUTOMATIC) Rx_irq,
    VAR(boolean, AUTOMATIC) Tx_irq
)
{
    VAR(uint8, AUTOMATIC)  u8ChannelCount = 0U;

    dwmac_dma_bus_init(ETH_CFG_CTRL_REG_BASE(CtrlIdx), DEFAULT_DMA_SYS);

    /*PRQA S 2877 2*/
    for (u8ChannelCount = 0; u8ChannelCount < ETH_MAX_DMA_CHANNEL; u8ChannelCount++) {
        /* DMA Control */
        dwmac_dma_init_channel(ETH_CFG_CTRL_REG_BASE(CtrlIdx), u8ChannelCount, DESC_SKIP_SIZE);
        /* ring length */
        dwmac_set_rx_ring_len(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                              MAX_ETH_RING_LENTH - 1, u8ChannelCount);
        /* ring base address */
        dwmac_dma_init_rx_chan(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                               soc_to_dma_address((uint32)Eth_Desc_Buf[CtrlIdx][u8ChannelCount][DESC_RX].desc),
                               u8ChannelCount);
        // rx bufize
        dwmac_set_bfsize(ETH_CFG_CTRL_REG_BASE(CtrlIdx), ETH_CFG_CTRL_MTU(CtrlIdx),
                         RX_CHANNEL_IDX(CtrlIdx, u8ChannelCount));
        // ring length
        dwmac_set_tx_ring_len(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                              MAX_ETH_RING_LENTH - 1, u8ChannelCount);
        // ring base address
        dwmac_dma_init_tx_chan(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                               soc_to_dma_address((uint32)Eth_Desc_Buf[CtrlIdx][u8ChannelCount][DESC_TX].desc),
                               u8ChannelCount);
        // ring tail ptr
        dwmac_set_tx_tail_ptr(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                              soc_to_dma_address((uint32)Eth_Desc_Buf[CtrlIdx][u8ChannelCount][DESC_TX].desc), \
                              u8ChannelCount);
        // enable irq
        dwmac_enable_dma_irq(ETH_CFG_CTRL_REG_BASE(CtrlIdx), u8ChannelCount, Rx_irq, Tx_irq);
    }
}
/**
 * @brief Sets the operating mode of an Ethernet controller.
 *
 * This function changes the operating mode of an Ethernet controller by starting or stopping
 * the receive and transmit DMA channels as needed.
 *
 * @param CtrlIdx The index of the Ethernet controller for which the mode is being set.
 * @param CtrlMode The desired operating mode of the Ethernet controller,
 *                  specified by the `Eth_ModeType` enum.
 *
 * @note This function iterates over all DMA channels (up to `ETH_MAX_DMA_CHANNEL`), starting or
 *       stopping the receive and transmit DMA channels based on the `CtrlMode` parameter.
 *       If `CtrlMode` is `ETH_MODE_ACTIVE`, it starts the receive and transmit DMA channels.
 *       If `CtrlMode` is not `ETH_MODE_ACTIVE`, it disables all DMA interrupts, stops the receive
 *       DMA channel, and stops all transmit DMA channels.
 */
LOCAL_INLINE FUNC(void, ETH_CODE) Eth_Set_Ctrl_Mode
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(Eth_ModeType, AUTOMATIC) CtrlMode
)
{
    VAR(uint8, AUTOMATIC)  u8ChannelCount = 0U;

    /*PRQA S 2877 2*/
    for (u8ChannelCount = 0; u8ChannelCount < ETH_MAX_DMA_CHANNEL; u8ChannelCount++) {
        if (CtrlMode == ETH_MODE_ACTIVE) {
            // start rx
            dwmac_dma_start_rx(ETH_CFG_CTRL_REG_BASE(CtrlIdx), RX_CHANNEL_IDX(CtrlIdx, u8ChannelCount));
            // start tx
            dwmac_dma_start_tx(ETH_CFG_CTRL_REG_BASE(CtrlIdx), u8ChannelCount);
        } else {
            // disable all irqs src
            dwmac_disable_all_irqs(ETH_CFG_CTRL_REG_BASE(CtrlIdx), u8ChannelCount);
            // stop rx
            dwmac_dma_stop_rx(ETH_CFG_CTRL_REG_BASE(CtrlIdx), RX_CHANNEL_IDX(CtrlIdx, u8ChannelCount));
            // stop tx
            dwmac_dma_stop_tx(ETH_CFG_CTRL_REG_BASE(CtrlIdx), u8ChannelCount);
        }
    }
}
/**
 * @brief Initializes the MTL (Media Transmission Layer) configuration for the specified Ethernet controller.
 *
 * This function initializes the MTL configuration for the specified Ethernet controller, including
 * configuring the receive arbitration algorithm, transmit scheduling algorithms, and per-channel
 * transmit settings. It configures the MTL to work with the DMA (Direct Memory Access) engine,
 * mapping MTL queues to DMA channels and enabling receive queues.
 *
 * @param CtrlIdx The index of the Ethernet controller for which to initialize the MTL configuration.
 *
 * @note The function assumes that the `ETH_CFG_CTRL_PARM_PTR` and `ETH_CFG_CTRL_REG_BASE` macros are
 *       defined and provide access to the configuration parameters and register base address of the
 *       specified Ethernet controller, respectively.
 *
 * @note The function configures the MTL based on the configuration data stored in the
 *       `Eth_CntrlConfigType` structure pointed to by the `CntrlConfig` parameter. This structure
 *       contains information such as the transmit traffic algorithms, memory policies, and per-channel
 *       configuration data.
 *
 * @note The function uses various hardware-specific functions (e.g., `dwmac_prog_mtl_rx_algorithms`,
 *       `dwmac_prog_mtl_tx_algorithms`, etc.) to program the MTL registers.
 *
 * @warning The caller must ensure that the `CtrlIdx` parameter is valid and corresponds to an
 *          initialized Ethernet controller.
 *
 * @warning The function does not perform any checks on the validity or completeness of the
 *          configuration data stored in the `Eth_CntrlConfigType` structure.
 */
FUNC(void, ETH_CODE) Eth_Ctrl_Init_MTL
(
    VAR(uint8, AUTOMATIC) CtrlIdx
)
{
    VAR(uint8, AUTOMATIC) u8ChannelCount = 0U;
    VAR(uint32, AUTOMATIC) u32ChannelWeight;
    VAR(uint32, AUTOMATIC) u32ChannelMemsize;
    const Eth_CntrlConfigType *CntrlConfig = ETH_CFG_CTRL_PARM_PTR(CtrlIdx);
    const Eth_EgressQueueCBSType *Cbscfg;
    /*
        P1359 num 1 config receive arbitration algorithm  cha 8.8
    */
    dwmac_prog_mtl_rx_algorithms(ETH_CFG_CTRL_REG_BASE(CtrlIdx), MTL_RX_ALGORITHM_SP);
    /*
        P1359 num 1 config Tx scheduling. More inifo at cha 8.10
    */
    dwmac_prog_mtl_tx_algorithms(ETH_CFG_CTRL_REG_BASE(CtrlIdx), CntrlConfig->TxTrafficAlgorithms);

    /*PRQA S 2877 2*/
    for (u8ChannelCount = 0; u8ChannelCount < ETH_MAX_DMA_CHANNEL; u8ChannelCount++) {
        /* per channel config */
        Cbscfg = &CntrlConfig->CbsCfg[u8ChannelCount];

        if (CntrlConfig->MtlQueueMemPolicy != MTL_MEM_POLICY_DEFAULT) {
            u32ChannelMemsize = Cbscfg->MemSize;
        } else {
            u32ChannelMemsize = FIFO_ALLOC_MUL(tx_queue_mem_tbl[ETH_MAX_DMA_CHANNEL - 1][u8ChannelCount]);
        }

        dwmac_dma_tx_chan_op_mode(ETH_CFG_CTRL_REG_BASE(CtrlIdx), u8ChannelCount,
                                  u32ChannelMemsize, CntrlConfig->TrafficShaper);

        if (CntrlConfig->TxTrafficAlgorithms == MTL_TX_ALGORITHM_SP) {
            dwmac_dma_tx_chan_weight(ETH_CFG_CTRL_REG_BASE(CtrlIdx), u8ChannelCount, u8ChannelCount);
        }

        if (CntrlConfig->TrafficShaper == MTL_QUEUE_MODE_AVB) {
            /*PRQA S 2991,2995 2*/
            if (0u == u8ChannelCount)
                continue;

            if (CntrlConfig->TxTrafficAlgorithms == MTL_TX_ALGORITHM_CC) {
                /* config CBS and ETS not support */
                dwmac_mtl_tx_chan_set_cbs(ETH_CFG_CTRL_REG_BASE(CtrlIdx),
                                          u8ChannelCount, Cbscfg->idleSlopeOrWeight,
                                          Cbscfg->sendSlope, Cbscfg->hiCredit, Cbscfg->loCredit);
            } else if (CntrlConfig->TxTrafficAlgorithms == MTL_TX_ALGORITHM_SP) {
                dwmac_mtl_tx_chan_set_sp_mode(ETH_CFG_CTRL_REG_BASE(CtrlIdx), u8ChannelCount);
            }
        } else {
            /* weight */

            if (CntrlConfig->TxTrafficAlgorithms == MTL_TX_ALGORITHM_WFQ) {
                u32ChannelWeight = DCB_WFQ_WHT(Cbscfg->idleSlopeOrWeight);
            } else {
                u32ChannelWeight = Cbscfg->idleSlopeOrWeight;
            }
            dwmac_mtl_tx_chan_set_weight(ETH_CFG_CTRL_REG_BASE(CtrlIdx),CntrlConfig->TxTrafficAlgorithms,
                u8ChannelCount, u32ChannelWeight);
        }

    }

    /* rx only enable one queue */
    /* mtl map with dma */
    dwmac_map_mtl_dma(ETH_CFG_CTRL_REG_BASE(CtrlIdx), MULTI_CH_RX_CH_IDX, MULTI_CH_RX_CH_IDX);
    dwmac_rx_queue_enable(ETH_CFG_CTRL_REG_BASE(CtrlIdx), MTL_QUEUE_MODE_DCB, MULTI_CH_RX_CH_IDX);

#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
    if ((TRUE == ETH_CFG_CTRL_RXQ_DRCT_ENABLE(CtrlIdx)) && (ETH_DIRECT_FORWARD_RX_CHANNEL > MULTI_CH_RX_CH_IDX)) {
        dwmac_dma_rx_chan_op_mode(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                                  MULTI_CH_RX_CH_IDX,MTL_QUEUE_SIZE/2, MTL_QUEUE_MODE_DCB);
        dwmac_map_mtl_dma(ETH_CFG_CTRL_REG_BASE(CtrlIdx), ETH_DIRECT_FORWARD_RX_CHANNEL, ETH_DIRECT_FORWARD_RX_CHANNEL);
        dwmac_rx_queue_enable(ETH_CFG_CTRL_REG_BASE(CtrlIdx), MTL_QUEUE_MODE_DCB, ETH_DIRECT_FORWARD_RX_CHANNEL);
        dwmac_dma_rx_chan_op_mode(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                                  ETH_DIRECT_FORWARD_RX_CHANNEL,MTL_QUEUE_SIZE/2, MTL_QUEUE_MODE_DCB);
    }
    else {
        dwmac_dma_rx_chan_op_mode(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                                  MULTI_CH_RX_CH_IDX,MTL_QUEUE_SIZE, MTL_QUEUE_MODE_DCB);
    }
#else
    dwmac_dma_rx_chan_op_mode(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                              MULTI_CH_RX_CH_IDX,MTL_QUEUE_SIZE, MTL_QUEUE_MODE_DCB);
#endif

}
/**
 * @brief Initializes the MAC (Media Access Control) layer for an Ethernet controller.
 *
 * This function initializes the MAC layer for an Ethernet controller, including configuring the MTU (Maximum
 * Transmission Unit), link speed, MAC address, and other relevant registers. It also configures optional
 * features such as PTP (Precision Time Protocol) support, depending on compile-time configurations.
 *
 * @param CtrlIdx The index of the Ethernet controller for which the MAC layer is being initialized.
 * @param Mtu The Maximum Transmission Unit (MTU) size in bytes.
 * @param Speed The desired link speed for the Ethernet controller, specified by an enumeration.
 *
 * @note The function maps the specified link speed (`Speed`) to the corresponding PHY speed constant
 *       (e.g., `PHY_SPEED_1000` for 1Gbps) and initializes the MAC layer accordingly. It also configures
 *       the MAC address using the `ETH_CFG_CTRL_MAC_ADDR_HIGH` and `ETH_CFG_CTRL_MAC_ADDR_LOW` macros,
 *       which are assumed to return the upper and lower halves of the 48-bit MAC address, respectively.
 *
 *       If PTP support is enabled (`ETH_GET_GLOBALTIME_API` is defined), the function additionally
 *       initializes the PTP-related registers and configures the PTP version, mode, and receive filters
 *       based on the configuration provided in the `Eth_CntrlConfigType` structure.
 */
FUNC(void, ETH_CODE) Eth_Ctrl_Init_MAC
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint32, AUTOMATIC) Mtu,
    VAR(uint32, AUTOMATIC) Speed
)
{
    // Initialize the MAC speed variable to 1Gbps (Gigabit per second) as a default.
    // This value will be overridden based on the Speed parameter.
    uint32 mac_speed = PHY_SPEED_1000;

    // If PTP (Precision Time Protocol) support is enabled (as indicated by the STD_ON == ETH_GET_GLOBALTIME_API condition),
    // retrieve the configuration for the current Ethernet controller instance.
#if STD_ON == ETH_GET_GLOBALTIME_API
    const Eth_CntrlConfigType *CntrlConfig = ETH_CFG_CTRL_PARM_PTR(CtrlIdx);
#endif

    // Based on the Speed parameter, set the appropriate PHY speed constant for the MAC layer.
    switch (Speed) {
    case ETH_MAC_LAYER_SPEED_10M:
        // Set MAC speed to 10Mbps
        mac_speed = PHY_SPEED_10;
        break;

    case ETH_MAC_LAYER_SPEED_100M:
        // Set MAC speed to 100Mbps
        mac_speed = PHY_SPEED_100;
        break;

    case ETH_MAC_LAYER_SPEED_1G:
        // Set MAC speed to 1Gbps (this is the default, but included for completeness)
        mac_speed = PHY_SPEED_1000;
        break;

    default:
        // If an unrecognized Speed value is provided, no action is taken, and mac_speed remains at its default value.
        // This may be a design choice or an oversight; consider adding an error handling mechanism if desired.
        break;
    }

#if STD_ON == ETH_DIRECT_FORWARD_ENABLE
    if (TRUE == ETH_CFG_CTRL_BCDUP_ENABLE(CtrlIdx)) {
        dwmac_set_packet_dup_enable(ETH_CFG_CTRL_REG_BASE(CtrlIdx));
    }
#endif

    /* MAC reg */
    dwmac_core_init(ETH_CFG_CTRL_REG_BASE(CtrlIdx), Mtu, \
                    ETH_CFG_CTRL_MAC_ADDR_HIGH(CtrlIdx), \
                    ETH_CFG_CTRL_MAC_ADDR_LOW(CtrlIdx), \
                    mac_speed);

    // Configure the MAC layer to disable multicast and broadcast frame routing to the RX queue.
    // The second parameter (0) indicates that routing to the RX queue is disabled.
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
    dwmac_mac_rx_queue_mcbc_routing(ETH_CFG_CTRL_REG_BASE(CtrlIdx), RX_CHANNEL_IDX(CtrlIdx, ETH_DIRECT_FORWARD_RX_CHANNEL));
#else
    dwmac_mac_rx_queue_mcbc_routing(ETH_CFG_CTRL_REG_BASE(CtrlIdx), MULTI_CH_RX_CH_IDX);
#endif

    // If PTP support is enabled, initialize PTP-related registers and configure PTP settings.
#if STD_ON == ETH_GET_GLOBALTIME_API
    // Initialize system time registers (parameters may vary based on implementation)
    dwmac_init_systime(ETH_CFG_CTRL_REG_BASE(CtrlIdx), 0, 0);
    // Configure the sub-second increment rate for PTP
    config_sub_second_increment(ETH_CFG_CTRL_REG_BASE(CtrlIdx), ETH_SEC_REF_RATE);
    // Configure PTP timestamp filters
    setup_timestamp_filter(ETH_CFG_CTRL_REG_BASE(CtrlIdx),
                           CntrlConfig->ptp_version, CntrlConfig->ptp_mode, CntrlConfig->rxfilter);
#endif

}
/**
 * @brief Selects the MII (Media Independent Interface) type for an Ethernet controller.
 *
 * This function determines the appropriate MII type (e.g., RGMII, RMII) for an Ethernet controller based
 * on the specified type and subtype parameters. It supports selecting between XGMII, XMII, and other
 * MII types, but only RGMII and RMII are currently implemented.
 *
 * @param module  The index or identifier of the Ethernet controller module.
 * @param type    The type of MII interface to select, specified by the `ETH_MAC_LAYER_TYPE_` constants.
 * @param subtype The subtype of the MII interface, if applicable. For example, a reduced version of XGMII.
 *
 * @return Returns 0 on success (MII type selected successfully), or -1 if the specified type or subtype
 *         is not supported.
 *
 * @note This function currently only supports selecting between RGMII and RMII interfaces. Other MII types
 *       and subtypes are either not supported or not explicitly handled in this implementation.
 *
 *       If the function successfully selects an MII type, it calls the `select_eth_mii_type` function to
 *       apply the configuration to the specified Ethernet controller module.
 *
 *       The function assumes that the `ETH_CFG_CTRL_REG_BASE` macro is defined and returns the appropriate
 *       register base address for the specified Ethernet controller module.
 */
LOCAL_INLINE FUNC(sint32, ETH_CODE) Eth_Select_Mii_Type
(
    VAR(uint32, AUTOMATIC) module,
    VAR(uint32, AUTOMATIC) type,
    VAR(uint32, AUTOMATIC) subtype
)
{
    sint32 ret = 0;

    // Define the MII type
    uint32 eth_mii_type = ETH_PHY_INTF_SEL_RGMII;

    // Check if the type is XGMII
    if (type == ETH_MAC_LAYER_TYPE_XGMII) {
        // Check if the subtype is reduced
        if (subtype == REDUCED) {
            // Set the MII type to RGMII
            eth_mii_type = ETH_PHY_INTF_SEL_RGMII;
        } else {
            // Return an error
            ret = -1;
        }
    // Check if the type is XMII
    } else if (type == ETH_MAC_LAYER_TYPE_XMII) {
        // Check if the subtype is serial
        if (subtype == SERIAL) {
            // Not supported
            ret = -1;
        } else {
            // Set the MII type to RMII
            eth_mii_type = ETH_PHY_INTF_SEL_RMII;
        }
    // Check if the type is not supported
    } else {
        // Not supported
        ret = -1;
    }

    // If no error occurred
    if (ret == 0) {
        // Select the MII type
        select_eth_mii_type(ETH_CFG_CTRL_REG_BASE(module), eth_mii_type);
    }

    // Return the result
    return ret;
}

#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE_FAST
#include "Eth_MemMap.h"

/**
 * @brief Checks the validity and state of an Ethernet controller instance.
 *
 * This function performs several checks to ensure that the specified Ethernet controller instance is
 * valid and in a proper state for further operations. It checks the controller index against the
 * maximum number of supported controllers, verifies that the controller has been initialized, and
 * optionally checks if the current core has access to the controller.
 *
 * @param CtrlIdx The index of the Ethernet controller to check.
 * @param Sid     A unique session or service identifier associated with the operation.
 *
 * @return Returns `E_OK` if the controller is valid and in a proper state, or `E_NOT_OK` if an error
 *         is detected. If error detection is enabled (`ETH_DEV_ERROR_DETECT` is defined), specific
 *         error codes may be reported using the `Det_ReportError` function.
 *
 * @note The function assumes that `ETH_MAXCTRLS_SUPPORTED` defines the maximum number of supported
 *       Ethernet controller instances, and `ETH_CTRL_STATE` is a macro or function that returns the
 *       current state of the specified controller instance.
 *
 *       If `ETH_DEV_ERROR_DETECT` is defined, the function will report errors using the `Det_ReportError`
 *       function, which is expected to be provided by the error detection and reporting system. The
 *       reported errors include invalid controller index (`ETH_E_INV_CTRL_IDX`), uninitialized
 *       controller (`ETH_E_UNINIT`), and access resource conflict (`ETH_E_ACCESS_RES`).
 *
 *       The function also checks if the current core has access to the specified controller instance,
 *       but this check is only performed if `ETH_DEV_ERROR_DETECT` is defined.
 */
// This function checks if the given control index and service ID are valid
static inline Std_ReturnType Eth_Det_Check(uint8 CtrlIdx, uint8 Sid)
{
    // Initialize the return value to E_OK
    Std_ReturnType RetVal = E_OK;

    // Check if the control index is valid
    if (CtrlIdx >= (VAR(uint8, AUTOMATIC))ETH_MAXCTRLS_SUPPORTED) {
#if STD_ON == ETH_DEV_ERROR_DETECT
        // If the control index is invalid, report an error
        (void)Det_ReportError ( \
                                (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                Sid, ETH_E_INV_CTRL_IDX \
                              );
#endif /* ETH_DEV_ERROR_DETECT  */
        // Set the return value to E_NOT_OK
        RetVal = E_NOT_OK;
    } else if (ETH_STATE_INIT != ETH_CTRL_STATE(CtrlIdx)) {
#if STD_ON == ETH_DEV_ERROR_DETECT
        // If the control index is valid but the state is not initialized, report an error
        (void)Det_ReportError ( \
                                (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                Sid, ETH_E_UNINIT \
                              );
#endif /* ETH_DEV_ERROR_DETECT  */
        // Set the return value to E_NOT_OK
        RetVal = E_NOT_OK;
    }
#if STD_ON == ETH_DEV_ERROR_DETECT

    // Check if the current core can access the control index
    else if (Eth_CheckCurCoreCanAccess(CtrlIdx, Eth_GetCoreID()) != E_OK) {

        // If the current core cannot access the control index, report an error
        (void)Det_ReportError ( \
                                (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                Sid, ETH_E_ACCESS_RES \
                              );
        // Set the return value to E_NOT_OK
        RetVal = E_NOT_OK;
    }

#endif /* ETH_DEV_ERROR_DETECT  */

    // Return the return value
    return RetVal;
}
/**
 * @brief Checks the validity of a transmit buffer index for an Ethernet controller.
 *
 * This function performs a parameter check to ensure that the specified transmit buffer index is
 * valid for the given Ethernet controller instance. It considers the maximum number of transmit
 * buffers supported by each controller and the current controller index.
 *
 * @param CtrlIdx     The index of the Ethernet controller for which the transmit buffer is intended.
 * @param BufferIdx   The index of the transmit buffer to check.
 * @param Sid         A unique session or service identifier associated with the operation.
 *
 * @return Returns `E_OK` if the buffer index is valid for the specified controller, or `E_NOT_OK` if
 *         the buffer index is out of range for the controller. If error detection is enabled
 *         (`ETH_DEV_ERROR_DETECT` is defined), an error report will be generated for invalid buffer
 *         indices.
 *
 * @note The function assumes that `CTRL0_TX_BUFF_COUNT` and `CTRL1_TX_BUFF_COUNT` define the maximum
 *       number of transmit buffers supported by the first and second (if present) Ethernet controller
 *       instances, respectively. If `ETH_MAXCTRLS_SUPPORTED` is set to a value greater than 2,
 *       additional checks for additional controllers would need to be added.
 *
 *       If `ETH_DEV_ERROR_DETECT` is defined, the function will report invalid parameter errors
 *       (`ETH_E_INV_PARAM`) using the `Det_ReportError` function, which is expected to be provided
 *       by the error detection and reporting system.
 */
static inline Std_ReturnType Eth_Transmit_Det_Check(uint8 CtrlIdx,Eth_BufIdxType BufferIdx,uint8 Sid)
{
    // Initialize the return value to OK
    Std_ReturnType RetVal = E_OK;

    // Check if the control index is 0 and the buffer index is greater than or equal to the number of transmission buffers for control 0
    if(0u == CtrlIdx && BufferIdx >= CTRL0_TX_BUFF_COUNT){
        // Set the return value to NOT OK
        RetVal = E_NOT_OK;
    }
#if ETH_MAXCTRLS_SUPPORTED == 2U
    // Check if the control index is 1 and the buffer index is greater than or equal to the number of transmission buffers for control 1
    if(CtrlIdx == 1 && BufferIdx >= CTRL1_TX_BUFF_COUNT){
        // Set the return value to NOT OK
        RetVal = E_NOT_OK;
    }
#endif

#if STD_ON == ETH_DEV_ERROR_DETECT
    // If the return value is NOT OK, report the error
    if(RetVal == E_NOT_OK){
        (void)Det_ReportError ((uint8) ETH_MODULE_ID,
                            ETH_DRIVER_INSTANCE,
                            Sid,
                            ETH_E_INV_PARAM);
    }
#endif /* ETH_DEV_ERROR_DETECT  */

    // Return the return value
    return RetVal;
}
#define ETH_STOP_SEC_CODE_FAST
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE
#include "Eth_MemMap.h"


#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
#define ETH_DMA_MAD_NUM 6

void Eth_DmaCfgMad1(const Dma_ChannelConfigType *channel,
                    struct dma_desc *tx_desc,
                    struct dma_desc *rx_desc,
                    Dma_DeviceConfigType *dmaConfig)
{
    (void)Dma_InitConfigChannel(dmaConfig);
    dmaConfig->direction           = DMA_MEMORY_TO_MEMORY;
    dmaConfig->transaction         = DMA_CYCLIC; /* only mad1 need */
    dmaConfig->periodLength        = 8U; /* only mad1 need */
    dmaConfig->processMode         = DMA_INTERRUPT; /* only mad1 need */
    dmaConfig->srcAddress          = (uint32)soc_to_dma_address((uint32)&(rx_desc->des0));
    dmaConfig->dstAddress          = (uint32)soc_to_dma_address((uint32)&(tx_desc->des0));
    dmaConfig->srcBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->dstBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->srcMaxBurst         = DMA_BURST_LENGTH_2;
    dmaConfig->dstMaxBurst         = DMA_BURST_LENGTH_2;
    dmaConfig->srcPortSelect       = DMA_PORT_AXI64;
    dmaConfig->dstPortSelect       = DMA_PORT_AXI64;
    dmaConfig->srcIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->dstIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->srcStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->dstStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->bufferMode          = DMA_SINGLE_BUFFER;
    dmaConfig->loopMode            = DMA_LOOP_MODE_0;
    dmaConfig->flowControl         = DMA_DIR_MEMORY_TO_MEMORY;
    dmaConfig->transferMode        = DMA_TRANSFER_MODE_LINKLIST;
    dmaConfig->linkListTriggerMode = DMA_TRIGGER_BY_SOFTWARE;
    dmaConfig->multiMadNumber      = 6U; /* only mad1 need */
    dmaConfig->periodLength        = 8U; /* transfor data len */
    dmaConfig->secondOperationData = (uint32)&rx_desc->des3; /* only mad1 need */
    dmaConfig->gtimerSelect        = DMA_TIMER0; /* only mad1 need */
    dmaConfig->madLength           = 8U; /* only mad1 not need */

    /* only mad1 need */
    Dma_SetChannelPatternMatchMask(channel, 0x00000000, 0x80000000);
}

void Eth_DmaCfgMad2(struct dma_desc *tx_desc,
                    struct dma_desc *rx_desc,
                    Dma_DeviceConfigType *dmaConfig)
{
    (void)Dma_InitConfigChannel(dmaConfig);
    dmaConfig->direction           = DMA_MEMORY_TO_MEMORY;
    dmaConfig->srcAddress          = (uint32)soc_to_dma_address((uint32)&(rx_desc->des2));
    dmaConfig->dstAddress          = (uint32)soc_to_dma_address((uint32)&(tx_desc->des2));
    dmaConfig->srcBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->dstBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->srcMaxBurst         = DMA_BURST_LENGTH_2;
    dmaConfig->dstMaxBurst         = DMA_BURST_LENGTH_2;
    dmaConfig->srcPortSelect       = DMA_PORT_AXI64;
    dmaConfig->dstPortSelect       = DMA_PORT_AXI64;
    dmaConfig->srcIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->dstIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->srcStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->dstStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->bufferMode          = DMA_SINGLE_BUFFER;
    dmaConfig->loopMode            = DMA_LOOP_MODE_0;
    dmaConfig->flowControl         = DMA_DIR_MEMORY_TO_MEMORY;
    dmaConfig->transferMode        = DMA_TRANSFER_MODE_LINKLIST;
    dmaConfig->patternDetectMode   = DMA_PATTERN_DET_POLLING_OPD2_EXE_CUR_MAD;
    dmaConfig->linkListTriggerMode = DMA_TRIGGER_BY_INTERNAL_EVENT;
    dmaConfig->madLength           = 8U; /* transfor data len */
}

void Eth_DmaCfgMad3(uint32 tx_desc_addr,
                    uint32 tx_end_addr,
                    Dma_DeviceConfigType *dmaConfig)
{
    (void)Dma_InitConfigChannel(dmaConfig);
    dmaConfig->direction           = DMA_MEMORY_TO_DEVICE;
    dmaConfig->srcAddress          = (uint32)soc_to_dma_address(tx_desc_addr);
    dmaConfig->dstAddress          = (uint32)soc_to_dma_address(tx_end_addr);
    dmaConfig->srcBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->dstBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->srcMaxBurst         = DMA_BURST_LENGTH_1;
    dmaConfig->dstMaxBurst         = DMA_BURST_LENGTH_1;
    dmaConfig->srcPortSelect       = DMA_PORT_AXI64;
    dmaConfig->dstPortSelect       = DMA_PORT_AHB32;
    dmaConfig->srcIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->dstIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->srcStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->dstStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->bufferMode          = DMA_SINGLE_BUFFER;
    dmaConfig->loopMode            = DMA_LOOP_MODE_1;
    dmaConfig->flowControl         = DMA_DIR_MEMORY_TO_DEVICE;
    dmaConfig->transferMode        = DMA_TRANSFER_MODE_LINKLIST;
    dmaConfig->linkListTriggerMode = DMA_TRIGGER_BY_INTERNAL_EVENT;
    dmaConfig->madLength           = 4U; /* transfor data len */
}

void Eth_DmaCfgMad4(struct dma_desc *rx_desc,
                    struct dma_desc *rx_desc_back,
                    Dma_DeviceConfigType *dmaConfig)
{
    (void)Dma_InitConfigChannel(dmaConfig);
    dmaConfig->direction           = DMA_MEMORY_TO_MEMORY;
    dmaConfig->srcAddress          = (uint32)soc_to_dma_address((uint32)&(rx_desc_back->des0));
    dmaConfig->dstAddress          = (uint32)soc_to_dma_address((uint32)&(rx_desc->des0));
    dmaConfig->srcBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->dstBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->srcMaxBurst         = DMA_BURST_LENGTH_4;
    dmaConfig->dstMaxBurst         = DMA_BURST_LENGTH_4;
    dmaConfig->srcPortSelect       = DMA_PORT_AXI64;
    dmaConfig->dstPortSelect       = DMA_PORT_AXI64;
    dmaConfig->srcIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->dstIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->srcStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->dstStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->bufferMode          = DMA_SINGLE_BUFFER;
    dmaConfig->loopMode            = DMA_LOOP_MODE_0;
    dmaConfig->flowControl         = DMA_DIR_MEMORY_TO_MEMORY;
    dmaConfig->transferMode        = DMA_TRANSFER_MODE_LINKLIST;
    dmaConfig->linkListTriggerMode = DMA_TRIGGER_BY_INTERNAL_EVENT;
    dmaConfig->madLength           = 16U; /* transfor data len */
}


void Eth_DmaCfgMad5(uint32 rx_desc_addr,
                    uint32 rx_end_addr,
                    Dma_DeviceConfigType *dmaConfig)
{
    (void)Dma_InitConfigChannel(dmaConfig);
    dmaConfig->direction           = DMA_MEMORY_TO_DEVICE;
    dmaConfig->srcAddress          = (uint32)soc_to_dma_address(rx_desc_addr);
    dmaConfig->dstAddress          = (uint32)soc_to_dma_address(rx_end_addr);
    dmaConfig->srcBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->dstBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->srcMaxBurst         = DMA_BURST_LENGTH_1;
    dmaConfig->dstMaxBurst         = DMA_BURST_LENGTH_1;
    dmaConfig->srcPortSelect       = DMA_PORT_AXI64;
    dmaConfig->dstPortSelect       = DMA_PORT_AHB32;
    dmaConfig->srcIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->dstIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->srcStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->dstStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->bufferMode          = DMA_SINGLE_BUFFER;
    dmaConfig->loopMode            = DMA_LOOP_MODE_1;
    dmaConfig->flowControl         = DMA_DIR_MEMORY_TO_DEVICE;
    dmaConfig->transferMode        = DMA_TRANSFER_MODE_LINKLIST;
    dmaConfig->linkListTriggerMode = DMA_TRIGGER_BY_INTERNAL_EVENT;
    dmaConfig->madLength           = 4U; /* transfor data len */
}

void Eth_DmaCfgMad6(uint32 **opd2_data,
                    uint32 opd2_reg,
                    Dma_DeviceConfigType *dmaConfig)
{
    (void)Dma_InitConfigChannel(dmaConfig);
    dmaConfig->direction           = DMA_MEMORY_TO_DEVICE;
    dmaConfig->srcAddress          = (uint32)soc_to_dma_address((uint32)opd2_data);
    dmaConfig->dstAddress          = (uint32)soc_to_dma_address(opd2_reg);
    dmaConfig->srcBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->dstBusWidth         = DMA_BEAT_SIZE_4_BYTE;
    dmaConfig->srcMaxBurst         = DMA_BURST_LENGTH_1;
    dmaConfig->dstMaxBurst         = DMA_BURST_LENGTH_1;
    dmaConfig->srcPortSelect       = DMA_PORT_AXI64;
    dmaConfig->dstPortSelect       = DMA_PORT_AHB32;
    dmaConfig->srcIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->dstIncDirection     = DMA_BURST_INCREMENTAL;
    dmaConfig->srcStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->dstStridePol        = DMA_POSITIVE_OFFSET;
    dmaConfig->bufferMode          = DMA_SINGLE_BUFFER;
    dmaConfig->loopMode            = DMA_LOOP_MODE_1;
    dmaConfig->flowControl         = DMA_DIR_MEMORY_TO_DEVICE;
    dmaConfig->transferMode        = DMA_TRANSFER_MODE_LINKLIST;
    dmaConfig->linkListTriggerMode = DMA_TRIGGER_BY_INTERNAL_EVENT;
    dmaConfig->madLength           = 4U; /* transfor data len */
}

#define DMA_IP_CH_SECOND_OPERATION_DATA_REG                             (0x88U)
#define DMA_IP_CHANNEL_BASE_OFFSET                                      (0x10000U)
#define DMA_IP_CHANNEL_BANK(chann)                                      (((chann) >> 2U) + 1U)
/** \brief  CalUcate DMA channel base address. */
#define DMA_IP_CHANNEL_BASE(base, chann)                                ((0x2000UL * ((chann) % 4U)) + (base) + DMA_IP_CHANNEL_BASE_OFFSET * DMA_IP_CHANNEL_BANK(chann))

LOCAL_INLINE FUNC(void, ETH_CODE) Eth_Backup_RxDesp
(
    VAR(uint8, AUTOMATIC) CtrlIdx
)
{
    const Eth_DrctFwdConfigType *FwdCfg = Eth_FwdCfg;
    uint32 i = 0;

    for (i = 0; i < ETH_DIRECT_FORWARD_NUM; i++)
    {
        if (((ETH1ToETH2 == FwdCfg[i].direction) && (0 == CtrlIdx)) ||
            ((ETH2ToETH1 == FwdCfg[i].direction) && (1 == CtrlIdx)))
        {
            /* init rx desp backup */
            Mcal_MemCpy(&Eth_Desc_Buf_Rx_Backup[i],
                   &Eth_Desc_Buf[CtrlIdx][ETH_DIRECT_FORWARD_RX_CHANNEL][DESC_RX],
                   sizeof(dma_desc_ring_t));
        } /* don't need else */
    }
}

FUNC(void, ETH_CODE) Eth_Init_pktFilter
(
    VAR(void, AUTOMATIC)
)
{
    uint32 fwdIdx = 0;

    for (fwdIdx = 0; fwdIdx < ETH_DIRECT_FORWARD_NUM; fwdIdx++)
    {
        const Eth_DrctFwdConfigType *FwdCfg = Eth_FwdCfg;
        uint32 filterLoop = 0;
        uint8 filterIdx = 1; /* nomal macFilter occupy index 0 */
        uint8 SrcCtrlIdx = 0;

        if (ETH1ToETH2 == FwdCfg[fwdIdx].direction)
        {
            SrcCtrlIdx = 0; /* eth1 */
        }
        else if (ETH2ToETH1 == FwdCfg[fwdIdx].direction)
        {
            SrcCtrlIdx = 1; /* eth2 */
        } /* don't need else */

        const uint8 macFilterNum = FwdCfg[fwdIdx].macFilterNum;
        const Eth_MacFilterConfigType* macFilter = FwdCfg[fwdIdx].macFilter;
        if (TRUE == ETH_CFG_CTRL_SRCMAC_FILTER_ENABLE(SrcCtrlIdx))
        {
            dwmac_set_filter_enable(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx), MAC_PACKET_FILTER_SAF);
        }

        if (TRUE == ETH_CFG_CTRL_BCDUP_ENABLE(SrcCtrlIdx)) {
            for (filterLoop = 0; filterLoop < macFilterNum; filterLoop++)
            {
                dwmac_set_mac_filter(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx),
                            macFilter[filterLoop].MACAddrHigh, macFilter[filterLoop].MACAddrLow, filterIdx,
                            BIT(ETH_DIRECT_FORWARD_RX_CHANNEL),
                            macFilter[filterLoop].AddrEnable, macFilter[filterLoop].SourceAddr);
                filterIdx++;
            }
            /* enable broadcast duplication */
            dwmac_set_mac_filter(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx),
                            0xffff, 0xffffffff, filterIdx,
                            ((BIT(ETH_DIRECT_FORWARD_RX_CHANNEL)) | BIT(0)),
                            TRUE, FALSE);
        }
        else {
            for (filterLoop = 0; filterLoop < macFilterNum; filterLoop++)
            {
                dwmac_set_mac_filter(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx),
                            macFilter[filterLoop].MACAddrHigh, macFilter[filterLoop].MACAddrLow, filterIdx,
                            ETH_DIRECT_FORWARD_RX_CHANNEL,
                            macFilter[filterLoop].AddrEnable, macFilter[filterLoop].SourceAddr);
                filterIdx++;
            }
        }

        if (TRUE == FwdCfg[fwdIdx].vlanFilterEn)
        {
            dwmac_set_filter_enable(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx), MAC_PACKET_FILTER_VTFE);
            const uint8 vlanFilterNum = FwdCfg[fwdIdx].vlanFilterNum;
            const Eth_VlanFilterConfigType* vlanFilter = FwdCfg[fwdIdx].vlanFilter;
            for (filterLoop = 0; filterLoop < vlanFilterNum; filterLoop++)
            {
                dwmac_set_vlan_filter(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx),
                            vlanFilter[filterLoop].VlanId, filterLoop,
                            ETH_DIRECT_FORWARD_RX_CHANNEL);
            }
        }

        if (TRUE == FwdCfg[fwdIdx].portFilterEn)
        {
            dwmac_set_filter_enable(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx), MAC_PACKET_FILTER_IPFE);
            const uint8 portFilterNum = FwdCfg[fwdIdx].portFilterNum;
            const Eth_PortFilterConfigType* portFilter = FwdCfg[fwdIdx].portFilter;
            for (filterLoop = 0; filterLoop < portFilterNum; filterLoop++)
            {
                dwmac_set_port_filter(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx),
                            &portFilter[filterLoop], filterLoop,
                            ETH_DIRECT_FORWARD_RX_CHANNEL);
            }
        }
    }
}


/**
 * Determines the appropriate DMA hack size based on the given hackSize.
 *
 * This code uses a series of nested ternary operators to select the correct
 * DMA hack size constant based on the value of hackSize. The possible sizes
 * and their corresponding constants are:
 * - hackSize <= 128: SDRV_DMA_HACK_SIZE_128
 * - hackSize <= 256: SDRV_DMA_HACK_SIZE_256
 * - hackSize <= 512: SDRV_DMA_HACK_SIZE_512
 * - hackSize <= 1024: SDRV_DMA_HACK_SIZE_1K
 * - hackSize <= 2048: SDRV_DMA_HACK_SIZE_2K
 * - hackSize <= 4096: SDRV_DMA_HACK_SIZE_4K
 * - hackSize <= 8192: SDRV_DMA_HACK_SIZE_8K
 * - hackSize <= 16384: SDRV_DMA_HACK_SIZE_16K
 * - hackSize > 16384: SDRV_DMA_HACK_SIZE_32K
 *
 * @param hackSize The size to be evaluated.
 * @return The corresponding DMA hack size constant.
 */
LOCAL_INLINE FUNC(Dma_HackSizeType, ETH_CODE) Eth_Trans_HackSize
(
    VAR(int, AUTOMATIC) hackSize
)
{
    int configSize = SDRV_DMA_HACK_SIZE_128;
    int calcSize;

    if (hackSize > 16384) {
        configSize = SDRV_DMA_HACK_SIZE_32K;
    }
    else if (hackSize > 128) {
        configSize++;
        calcSize = (hackSize - 1) >> 8;
        while (calcSize) {
            configSize++;
            calcSize = calcSize >> 1;
        }
    } /* don't need else */

    return (Dma_HackSizeType)configSize;
}

extern const Dma_ConfigType Dma_ConfigRootTable;
FUNC(sint32, ETH_CODE) Eth_Init_drctFwd
(
    VAR(void, AUTOMATIC)
)
{
    const Eth_DrctFwdConfigType *FwdCfg = Eth_FwdCfg;
    sint32 ret = 0;
    uint32 fwdIdx = 0;
    uint32 descIdx = 0;
    uint32 dmaRingIdx = 0;
    uint8 SrcCtrlIdx = 0;
    uint8 DstCtrlIdx = 0;
    Dma_PeripheralIdType dmaType = DMA_ETH1ToETH2;
    Dma_HwControllerType dmaCont = DMA_HW_UNDEFINE;

    Dma_Init(&Dma_ConfigRootTable);


    for (fwdIdx = 0; fwdIdx < ETH_DIRECT_FORWARD_NUM; fwdIdx++)
    {
        if (ETH1ToETH2 == FwdCfg[fwdIdx].direction)
        {
            SrcCtrlIdx = 0; /* eth1 */
            DstCtrlIdx = 1; /* eth2 */
            dmaType = DMA_ETH1ToETH2;
        }
        else if (ETH2ToETH1 == FwdCfg[fwdIdx].direction)
        {
            SrcCtrlIdx = 1; /* eth2 */
            DstCtrlIdx = 0; /* eth1 */
            dmaType = DMA_ETH2ToETH1;
        } /* don't need else */

        /* disable fwd queue irq */
        dwmac_disable_specify_dma_irq(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx),
                                      ETH_DIRECT_FORWARD_RX_CHANNEL, TRUE);
        dwmac_disable_specify_dma_irq(ETH_CFG_CTRL_REG_BASE(DstCtrlIdx),
                                      ETH_DIRECT_FORWARD_TX_CHANNEL, FALSE);

        /* init dma */
        Dma_InstanceConfigType dmaALConfigParams;
        Dma_ChannelConfigType *channelPtr = NULL;
        Dma_DeviceConfigType dmaConfigarry[ETH_DMA_MAD_NUM];

        ethDma_tx_tail_desc[fwdIdx] = &Eth_Desc_Buf[DstCtrlIdx][ETH_DIRECT_FORWARD_TX_CHANNEL][DESC_TX].desc[MAX_ETH_RING_LENTH];
        ethDma_rx_tail_desc[fwdIdx] = &Eth_Desc_Buf[SrcCtrlIdx][ETH_DIRECT_FORWARD_RX_CHANNEL][DESC_RX].desc[MAX_ETH_RING_LENTH];

        for (descIdx = 0; descIdx < MAX_ETH_RING_LENTH; descIdx++)
        {
            dmaRingIdx = descIdx + DMA_ETH_RING0;
            Dma_GetConfigParams(dmaType, dmaRingIdx, DMA_MODULE_ETH, &dmaALConfigParams);
            if (dmaRingIdx == DMA_ETH_RING0)
            {
                dmaCont = dmaALConfigParams.controller;
            }
            else
            {
                if (dmaCont != dmaALConfigParams.controller)
                {
                    DBG("ERROR: %s %d dma config error.\r\n, __FUNCTION__, __LINE__");
                    ret = -1;
                    break;
                }
            }
            channelPtr = Dma_RequestChannelWithId(dmaALConfigParams.controller/* SF0 */, dmaALConfigParams.channelId/* id */);
            if (NULL == channelPtr)
            {
                DBG("ERROR: %s %d alloc channel failed.\r\n, __FUNCTION__, __LINE__");
                ret = -1;
                break;
            }

            struct dma_desc *tx_desc = &Eth_Desc_Buf[DstCtrlIdx][ETH_DIRECT_FORWARD_TX_CHANNEL][DESC_TX].desc[descIdx];
            struct dma_desc *rx_desc = &Eth_Desc_Buf[SrcCtrlIdx][ETH_DIRECT_FORWARD_RX_CHANNEL][DESC_RX].desc[descIdx];
            ethDma_opd2_data[fwdIdx][descIdx] = &(rx_desc->des3);
            struct dma_desc *rx_desc_back = &Eth_Desc_Buf_Rx_Backup[fwdIdx].desc[descIdx];

            Eth_DmaCfgMad1(channelPtr, tx_desc, rx_desc, &dmaConfigarry[0]);
            Eth_DmaCfgMad2(tx_desc, rx_desc, &dmaConfigarry[1]);
            Eth_DmaCfgMad3((uint32)&ethDma_tx_tail_desc[fwdIdx],
                           (uint32)(ETH_CFG_CTRL_REG_BASE(DstCtrlIdx) +
                                    DMA_CH_TX_END_ADDR(ETH_DIRECT_FORWARD_TX_CHANNEL)),
                            &dmaConfigarry[2]);
            Eth_DmaCfgMad4(rx_desc, rx_desc_back, &dmaConfigarry[3]);
            Eth_DmaCfgMad5((uint32)&ethDma_rx_tail_desc[fwdIdx],
                           (uint32)(ETH_CFG_CTRL_REG_BASE(SrcCtrlIdx) +
                                    DMA_CH_RX_END_ADDR(ETH_DIRECT_FORWARD_RX_CHANNEL)),
                           &dmaConfigarry[4]);
            Eth_DmaCfgMad6(&ethDma_opd2_data[fwdIdx][descIdx],
                           (DMA_IP_CHANNEL_BASE(dmaALConfigParams.controller, dmaALConfigParams.channelId) +
                                    DMA_IP_CH_SECOND_OPERATION_DATA_REG),
                           &dmaConfigarry[5]);
            Dma_ConfigChannel(channelPtr, dmaConfigarry);
            Dma_PrepareTransmission(channelPtr, 8);

            Dma_Start(channelPtr);
        }


        Dma_GtimerConfigType gtimerConfig = {
            .gtimerId = DMA_TIMER0,
            .prediv = FwdCfg[fwdIdx].prediv,
            .overFlowValue = FwdCfg[fwdIdx].overFlowValue,
            .enable = TRUE,
        };
        Dma_GtimerConfig(dmaALConfigParams.controller, &gtimerConfig);

        Dma_HackConfigType dmaHackConfig = {
            .size = SDRV_DMA_HACK_SIZE_512,
            .startAddr = (uint32)&Eth_Desc_Buf[DstCtrlIdx][ETH_DIRECT_FORWARD_TX_CHANNEL][DESC_TX].desc[0],//0x0fffffff mask
            .hackDes2 = 0x00000,
            .hackDes3 = 0x2c000,
            .crcStripDisable = 1,
            .enable = TRUE,
        };
        int hackSize = sizeof(struct dma_desc) * MAX_ETH_RING_LENTH;
        dmaHackConfig.size = Eth_Trans_HackSize(hackSize);

        Dma_HackConfig(dmaALConfigParams.controller, &dmaHackConfig);

        if (0 != ret)
        {
            break;
        }
    }

    return ret;
}
#endif /* ETH_DIRECT_FORWARD_ENABLE  */

/**
 * @brief Initializes the Ethernet driver for the current core and its associated controllers.
 *
 * This function initializes the Ethernet driver by configuring the specified controller instances
 * based on the provided configuration parameters. It handles core-specific initialization, selects
 * the appropriate MII (Media Independent Interface) type for each controller, resets the DMA cores,
 * initializes the DMA, MTL (Media Transmission Layer), and MAC (Media Access Control) components,
 * and performs access tests to ensure proper operation.
 *
 * @param CfgPtr A pointer to an `Eth_ConfigType` structure containing the configuration parameters
 *               for the Ethernet driver and its controllers.
 *
 * @note This function assumes that the `Eth_ConfigType` structure contains a `EthCoreConfig` array
 *       that maps core IDs to their respective configurations, including the maximum number of
 *       controllers and pointers to their configurations.
 *
 *       The function performs error checking and reports errors using the `Det_ReportError` function
 *       if error detection is enabled (`ETH_DEV_ERROR_DETECT` is defined).
 *
 *       The `Eth_Init_CtrlData` function is called to initialize controller-specific data, and the
 *       `Eth_Select_Mii_Type` function is used to select the appropriate MII type for each controller.
 *
 *       After initializing the DMA, MTL, and MAC components, the function performs an access test to
 *       ensure that the controllers are accessible and functioning properly. If the access test fails
 *       or if any other initialization step fails, the corresponding controller's state is set to
 *       `ETH_STATE_UNINIT`.
 *
 *       If the `ETH_NOT_RESET_DATABUFF` macro is defined, the function initializes the descriptor rings
 *       and buffers for the controllers that passed the access test.
 */
FUNC(void, ETH_CODE) Eth_Init
(
    P2CONST(Eth_ConfigType, AUTOMATIC, ETH_APPL_CONST) CfgPtr
)
{

    VAR(uint8, AUTOMATIC)  CtrlIdx = 0U;
    VAR(uint8, AUTOMATIC)  CoreId = 0U;
    VAR(sint32, AUTOMATIC)  reset_ret = 0U;
    VAR(uint8, AUTOMATIC)  CoreCntrlIdx = 0U;
    VAR(Std_ReturnType, AUTOMATIC)  ret = E_OK;
    P2VAR(const Eth_CntrlConfigType, AUTOMATIC, AUTOMATIC) LocalCfgPtr;
    P2VAR(const Eth_CoreConfigType, AUTOMATIC, AUTOMATIC) CoreConfig;

    if (NULL_PTR == CfgPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
        (void)Det_ReportError ( \
                                (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) ETH_SID_INIT, \
                                ETH_E_PARAM_POINTER \
                              );
#endif /* ETH_DEV_ERROR_DETECT  */
    } else {
        CoreId = Eth_GetCoreID();

        CoreConfig = CfgPtr->EthCoreConfig[CoreId];

        if (NULL_PTR == CoreConfig) {
            ret = E_NOT_OK;
        }

        if (E_OK == ret) {
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
            Eth_FwdCfg = CoreConfig->EthDrctFwdCfgPtr;
#endif /* ETH_DIRECT_FORWARD_ENABLE  */
            /* */
            for (CoreCntrlIdx = 0; CoreCntrlIdx < CoreConfig->EthMaxControllers; CoreCntrlIdx++)
            {
                /* config param */
                LocalCfgPtr = &CoreConfig->EthCntrlConfigPtr[CoreCntrlIdx];
                /* bound init data */
                CtrlIdx = Eth_Init_CtrlData(CoreCntrlIdx, LocalCfgPtr);

                /* hardware special init */
                if (Eth_Select_Mii_Type(CtrlIdx, \
                                        LocalCfgPtr->MacLayerType, \
                                        LocalCfgPtr->MacLayerSubType)) {
#if STD_ON == ETH_DEV_ERROR_DETECT
                    (void)Det_ReportError ( \
                                            (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                            ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) ETH_SID_INIT, \
                                            ETH_E_PARAM_POINTER \
                                          );
#endif  /* ETH_DEM_EVENT_DETECT  */
                    return;
                }

                dwmac_set_clock_delay(ETH_CFG_CTRL_REG_BASE(CtrlIdx),
                                      ETH_CFG_CTRL_RXC_DELAY(CtrlIdx),
                                      ETH_CFG_CTRL_TXC_DELAY(CtrlIdx));

                /* DMA core sw reset */
                reset_ret  = dwmac_dma_reset(ETH_CFG_CTRL_REG_BASE(CtrlIdx));

                if (reset_ret < 0) {
                    Dem_SetEventStatus((Dem_EventIdType)ETH_CFG_DEM_E_ACCESS(CtrlIdx), DEM_EVENT_STATUS_PREFAILED);
                } else {
                    /* DMA Init */
                    Eth_Ctrl_Init_DMA(CtrlIdx, ETH_CFG_CTRL_RX_INT_MODE(CtrlIdx),
                                      ETH_CFG_CTRL_TX_INT_MODE(CtrlIdx));
                    /* MTL Init */
                    Eth_Ctrl_Init_MTL(CtrlIdx);
                    /* MAC Init */
                    Eth_Ctrl_Init_MAC(CtrlIdx, LocalCfgPtr->Mtu, LocalCfgPtr->MacLayerSpeed);
                    /* Init soft Statistic */
                    Eth_Init_mmc_status(CtrlIdx);
                }

                /* Access test*/
                if (reset_ret != 0 || FALSE == Eth_Access_Test(CtrlIdx)) {
                    Dem_SetEventStatus((Dem_EventIdType)ETH_CFG_DEM_E_ACCESS(CtrlIdx), DEM_EVENT_STATUS_PREFAILED);
                    ETH_CTRL_STATE(CtrlIdx) = ETH_STATE_UNINIT;
                } else {
#if (ETH_NOT_RESET_DATABUFF == 1)
                    /* desc ring init */
                    desc_ring_init(CtrlIdx);
                    /* buffer init*/
                    EthBuffInit(CtrlIdx);
                    /* Init recved desc ring to hw */
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
                    if ((E_OK != Init_Recive_Ring(CtrlIdx, MULTI_CH_RX_CH_IDX)) ||
                        ((TRUE == ETH_CFG_CTRL_RXQ_DRCT_ENABLE(CtrlIdx)) &&
                         (ETH_DIRECT_FORWARD_RX_CHANNEL > MULTI_CH_RX_CH_IDX) &&
                         (E_OK != Init_Recive_Ring(CtrlIdx, ETH_DIRECT_FORWARD_RX_CHANNEL))))
#else
                    if (E_OK != Init_Recive_Ring(CtrlIdx, MULTI_CH_RX_CH_IDX))
#endif
                    {
                        /* The number of rx descriptors is greater than the number of rx buffers,
                        resulting in failed initialization */
                        ETH_CTRL_STATE(CtrlIdx) = ETH_STATE_UNINIT;
                    }
                    else
                    {
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
                        Eth_Backup_RxDesp(CtrlIdx);
#endif /* ETH_DIRECT_FORWARD_ENABLE  */
#endif
                        ETH_CTRL_STATE(CtrlIdx) = ETH_STATE_INIT;
#if (ETH_NOT_RESET_DATABUFF == 1)
                    }
#endif /* ETH_NOT_RESET_DATABUFF  */
                }
            }
        }
    }
}

/**
 * @brief Sets the operational mode of an Ethernet controller.
 *
 * This function sets the operational mode of the specified Ethernet controller to either `ETH_MODE_DOWN`
 * (disabled) or another mode specified by the `CtrlMode` parameter. Depending on the mode, it may
 * initialize or deinitialize descriptor rings and buffers. It also checks the controller's accessibility
 * and updates the controller's state and mode accordingly.
 *
 * @param CtrlIdx The index of the Ethernet controller to set the mode for.
 * @param CtrlMode The operational mode to set for the controller. This parameter should be one of the
 *                 `Eth_ModeType` enumeration values, such as `ETH_MODE_DOWN` to disable the controller.
 *
 * @return Returns `E_OK` if the controller's mode was successfully set, or `E_NOT_OK` if an error occurred
 *         during the operation (e.g., invalid controller index, failed access test, or insufficient
 *         resources to initialize descriptor rings and buffers).
 *
 * @note If the `ETH_NOT_RESET_DATABUFF` macro is defined as 0, the function will initialize or
 *       deinitialize descriptor rings and buffers as needed when setting the controller's mode to
 *       `ETH_MODE_DOWN` or enabling it, respectively. Otherwise, these steps are skipped.
 *
 *       The function first checks the validity of the controller index using the `Eth_Det_Check`
 *       function. If the check fails, the function returns `E_NOT_OK` immediately.
 *
 *       After successfully setting the controller's mode, the function updates the controller's state
 *       and mode variables and notifies the Ethernet interface layer using the `EthIf_CtrlModeIndication`
 *       function.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_SetControllerMode
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(Eth_ModeType, AUTOMATIC) CtrlMode
)
{
    Std_ReturnType RetVal = E_OK;

    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_SETCONTROLLERMODE);

    if (RetVal == E_OK) {
        if (CtrlMode == ETH_MODE_DOWN) {
            /* data buf ring deinit */
#if (ETH_NOT_RESET_DATABUFF == 0)
            EthBuffDeInit(CtrlIdx);
#endif
        } else {
#if (ETH_NOT_RESET_DATABUFF == 0)
            /* desc ring init */
            desc_ring_init(CtrlIdx);
            EthBuffInit(CtrlIdx);
            /* Init recved desc ring to hw */
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
            if ((E_OK != Init_Recive_Ring(CtrlIdx, MULTI_CH_RX_CH_IDX)) ||
                ((TRUE == ETH_CFG_CTRL_RXQ_DRCT_ENABLE(CtrlIdx)) &&
                 (ETH_DIRECT_FORWARD_RX_CHANNEL > MULTI_CH_RX_CH_IDX) &&
                 (E_OK != Init_Recive_Ring(CtrlIdx, ETH_DIRECT_FORWARD_RX_CHANNEL))))
#else
            if (E_OK != Init_Recive_Ring(CtrlIdx, MULTI_CH_RX_CH_IDX))
#endif
            {
                /* The number of rx descriptors is greater than the number of rx buffers,
                resulting in failed initialization */
                RetVal = E_NOT_OK;
            }
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
            else
            {
                Eth_Backup_RxDesp(CtrlIdx);
            }
#endif

#endif
        }

        // Check if the return value is not OK or if the Ethernet access test fails
        if (RetVal == E_NOT_OK || (!Eth_Access_Test(CtrlIdx))) {
            // Set the event status to pre-failed
            Dem_SetEventStatus((Dem_EventIdType)ETH_CFG_DEM_E_ACCESS(CtrlIdx), DEM_EVENT_STATUS_PREFAILED);
            // Set the return value to not OK
            RetVal = E_NOT_OK;
        }

        // If the return value is OK
        if (RetVal == E_OK) {
            // Set the control mode
            ETH_CTRL_MODE(CtrlIdx) = CtrlMode;
            // Set the Ethernet control mode
            Eth_Set_Ctrl_Mode(CtrlIdx, CtrlMode);
            // Indicate the control mode
            EthIf_CtrlModeIndication(CtrlIdx, CtrlMode);
        }
    }

    return RetVal;
}
/**
 * @brief Retrieves the current operational mode of an Ethernet controller.
 *
 * This function retrieves the operational mode of the specified Ethernet controller and stores it
 * in the provided pointer. It performs a validity check on the controller index using the
 * `Eth_Det_Check` function and ensures that the provided pointer is not `NULL`.
 *
 * @param CtrlIdx The index of the Ethernet controller whose mode is to be retrieved.
 * @param CtrlModePtr A pointer to a variable where the retrieved mode will be stored.
 *
 * @return Returns `E_OK` if the mode was successfully retrieved and stored, or `E_NOT_OK` if an error
 *         occurred (e.g., invalid controller index or `NULL` pointer).
 *
 * @note If the `ETH_DEV_ERROR_DETECT` macro is defined, the function will report a parameter error
 *       using the `Det_ReportError` function if the provided pointer is `NULL`.
 *
 *       The function assumes that the `ETH_CTRL_MODE` macro or similar mechanism is used to access
 *       the operational mode of the specified controller.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_GetControllerMode
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    P2VAR(Eth_ModeType, AUTOMATIC, ETH_APPL_CONST) CtrlModePtr
)
{
    Std_ReturnType RetVal = E_OK;
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETCONTROLLERMODE);

    if (RetVal == E_OK) {
        if (NULL_PTR == CtrlModePtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETCONTROLLERMODE, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        } else {
            *CtrlModePtr = ETH_CTRL_MODE(CtrlIdx);
        }
    }

    return RetVal;
}
/**
 * @brief Retrieves the physical address (MAC address) of an Ethernet controller.
 *
 * This function retrieves the physical address (MAC address) of the specified Ethernet controller
 * and stores it in the provided array. It performs a validity check on the controller index using
 * the `Eth_Det_Check` function and ensures that the provided array pointer is not `NULL`.
 *
 * @param CtrlIdx The index of the Ethernet controller whose physical address is to be retrieved.
 * @param AddrPtr A pointer to an array where the retrieved physical address will be stored.
 *                The array should be large enough to hold the MAC address (typically 6 bytes).
 *
 * @note This function does not return a status code to indicate success or failure directly.
 *       Instead, it uses the `Eth_Det_Check` function to validate the controller index and
 *       the `Det_ReportError` function (if error detection is enabled) to report a parameter error
 *       if the provided pointer is `NULL`.
 *
 *       The function assumes that the `dwmac_get_umac_addr` function is used to retrieve the MAC
 *       address from the specified controller's registers. The `ETH_CFG_CTRL_REG_BASE` macro or
 *       similar mechanism is used to obtain the base address of the controller's registers.
 */
FUNC(void, ETH_CODE) Eth_GetPhysAddr
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    P2VAR(uint8, AUTOMATIC, ETH_APPL_CONST) AddrPtr
)
{
    // Declare a variable to store the return value of the function
    Std_ReturnType RetVal = E_OK;
    // Call the Eth_Det_Check function to check if the function can be executed
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETPHYSADDR);

    // If the function can be executed
    if (RetVal == E_OK) {
        // If the address pointer is NULL
        if (NULL_PTR == AddrPtr) {
            // If the detection of errors is enabled
#if STD_ON == ETH_DEV_ERROR_DETECT
            // Report an error
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETPHYSADDR, ETH_E_PARAM_POINTER \
                                  );
#endif
        } else {
            // Call the dwmac_get_umac_addr function to get the physical address
            dwmac_get_umac_addr(ETH_CFG_CTRL_REG_BASE(CtrlIdx), AddrPtr, 0);
        }
    }
}

/**
 * @brief Sets the physical address (MAC address) of an Ethernet controller.
 *
 * This function sets the physical address (MAC address) of the specified Ethernet controller to
 * the value provided in the given array. It performs a validity check on the controller index using
 * the `Eth_Det_Check` function and ensures that the provided array pointer is not `NULL`.
 *
 * @param CtrlIdx The index of the Ethernet controller whose physical address is to be set.
 * @param AddrPtr A pointer to an array containing the new physical address to be set.
 *                The array should contain the MAC address in a format suitable for the hardware
 *                (typically 6 bytes).
 *
 * @note This function does not return a status code to indicate success or failure directly.
 *       Instead, it uses the `Eth_Det_Check` function to validate the controller index and
 *       the `Det_ReportError` function (if error detection is enabled) to report a parameter error
 *       if the provided pointer is `NULL`.
 *
 *       The function assumes that the `dwmac_set_umac_addr` function is used to set the MAC
 *       address in the specified controller's registers. The `ETH_CFG_CTRL_REG_BASE` macro or
 *       similar mechanism is used to obtain the base address of the controller's registers.
 */
FUNC(void, ETH_CODE) Eth_SetPhysAddr
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    P2CONST(uint8, AUTOMATIC, ETH_APPL_CONST) AddrPtr
)
{
    // Declare a variable to store the return value of the function
    Std_ReturnType RetVal = E_OK;
    // Check if the function is called with the correct SID
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_SETPHYSADDR);

    // If the function is called with the correct SID
    if (RetVal == E_OK) {
        // Check if the address pointer is NULL
        if (NULL_PTR == AddrPtr)  {
            // If the address pointer is NULL, report an error
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_SETPHYSADDR, ETH_E_PARAM_POINTER \
                                  );
#endif
        } else {
            // If the address pointer is not NULL, set the physical address
            dwmac_set_umac_addr(ETH_CFG_CTRL_REG_BASE(CtrlIdx), AddrPtr, 0);
        }
    }
}

#if STD_ON == ETH_UPDATE_FILTER_API
/**
 * @brief Updates the physical address (MAC address) filter of an Ethernet controller.
 *
 * This function updates the physical address filter of the specified Ethernet controller to either
 * add or remove a MAC address from the filter. It performs a validity check on the controller index
 * using the `Eth_Det_Check` function and ensures that the provided MAC address pointer is not `NULL`.
 *
 * @param CtrlIdx The index of the Ethernet controller whose physical address filter is to be updated.
 * @param PhysAddrPtr A pointer to an array containing the MAC address to be added or removed from
 *                    the filter. The array should contain the MAC address in a format suitable for
 *                    the hardware (typically 6 bytes).
 * @param Action Specifies the action to perform on the filter: add or remove the MAC address.
 *
 * @return Returns `E_OK` if the filter was successfully updated, or `E_NOT_OK` if an error occurred
 *         (e.g., invalid controller index, `NULL` pointer, or failed filter update).
 *
 * @note This function assumes that the `dwmac_set_filter` function is used to update the physical
 *       address filter in the specified controller's registers. The `ETH_CFG_CTRL_REG_BASE` macro or
 *       similar mechanism is used to obtain the base address of the controller's registers.
 *
 *       The `dwmac_set_filter` function's return value is checked to determine if the filter update
 *       was successful. If the function returns a non-zero value, indicating an error, the function
 *       returns `E_NOT_OK`.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_UpdatePhysAddrFilter
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    P2CONST(uint8, AUTOMATIC, ETH_APPL_CONST) PhysAddrPtr,
    Eth_FilterActionType Action
)
{
    // Declare a return value variable
    Std_ReturnType RetVal = E_OK;
    // Check if the control index is valid
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_UPDATEADDRFILTER);

    // If the control index is valid
    if (RetVal == E_OK) {
        // Check if the physical address pointer is NULL
        if (NULL_PTR == PhysAddrPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            // If the physical address pointer is NULL, report an error
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_UPDATEADDRFILTER, ETH_E_PARAM_POINTER \
                                  );
#endif
            // Set the return value to not OK
            RetVal = E_NOT_OK;
        } else {
            // If the physical address pointer is not NULL, set the filter
            if (dwmac_set_filter(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                                 (uint32)Action, PhysAddrPtr)) {
                // If the filter setting fails, set the return value to not OK
                RetVal = E_NOT_OK;
            }
        }
    }

    // Return the return value
    return RetVal;
}
#endif

#if (STD_ON == ETH_CTRL_MII_ENABLE_API)
/**
 * @brief Writes a value to a specified MII/MDIO register of an Ethernet controller.
 *
 * This function writes a 16-bit value to a specified MII/MDIO register of the Ethernet controller
 * associated with the given controller index and transceiver index. It performs a validity check
 * on the controller index (optional, depending on the `MDIO_DET_CHECK_BYPASS` macro) and then
 * attempts to write the value to the register using the `mac_mdio_write` function.
 *
 * @param CtrlIdx The index of the Ethernet controller to which the MII/MDIO register belongs.
 * @param TrcvIdx The index of the transceiver associated with the MII/MDIO register.
 * @param RegIdx The index of the MII/MDIO register to write to.
 * @param RegVal The 16-bit value to write to the register.
 *
 * @return Returns `E_OK` if the value was successfully written to the register, or `E_NOT_OK` if
 *         an error occurred (e.g., invalid controller index, failed register write, or if the
 *         `MDIO_DET_CHECK_BYPASS` macro is not defined and the controller index check fails).
 *
 * @note The `MDIO_DET_CHECK_BYPASS` macro controls whether the controller index validity check
 *       is performed. If the macro is defined as `STD_OFF`, the check is bypassed.
 *
 *       The function assumes that the `mac_mdio_write` function is used to write to the MII/MDIO
 *       register. The `ETH_CFG_CTRL_REG_BASE` macro or similar mechanism is used to obtain the
 *       base address of the controller's registers.
 *
 *       If the register write is successful, the `EthTrcv_WriteMiiIndication` function is called
 *       to indicate the write operation.
 */
/*PRQA S 1557 20*/
FUNC(Std_ReturnType, ETH_CODE) Eth_WriteMii(VAR(uint8, AUTOMATIC) CtrlIdx, \
        VAR(uint8, AUTOMATIC) TrcvIdx, \
        VAR(uint8, AUTOMATIC) RegIdx, \
        VAR(uint16, AUTOMATIC) RegVal)
{
    Std_ReturnType RetVal = E_OK;
#if STD_OFF == MDIO_DET_CHECK_BYPASS
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_WRITEMII);
#endif

    if (RetVal == E_OK) {
        if (mac_mdio_write(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                           TrcvIdx, PHY_CLAUSE_22, RegIdx, RegVal)) {
            RetVal =  E_NOT_OK;
        }else{
            EthTrcv_WriteMiiIndication(CtrlIdx, TrcvIdx, RegIdx);
        }
    }

    return RetVal;
}

/**
 * @brief Reads a value from a specified MII/MDIO register of an Ethernet controller.
 *
 * This function reads a 16-bit value from a specified MII/MDIO register of the Ethernet controller
 * associated with the given controller index and transceiver index. It performs a validity check
 * on the controller index (optional, depending on the `MDIO_DET_CHECK_BYPASS` macro) and then
 * attempts to read the value from the register using the `mac_mdio_read` function.
 *
 * @param CtrlIdx The index of the Ethernet controller from which the MII/MDIO register value is to
 *                be read.
 * @param TrcvIdx The index of the transceiver associated with the MII/MDIO register.
 * @param RegIdx The index of the MII/MDIO register to read from.
 * @param RegValPtr A pointer to a variable where the read value will be stored.
 *
 * @return Returns `E_OK` if the value was successfully read from the register and stored in the
 *         provided pointer, or `E_NOT_OK` if an error occurred (e.g., invalid controller index,
 *         `NULL` pointer, or failed register read).
 *
 * @note The `MDIO_DET_CHECK_BYPASS` macro controls whether the controller index validity check
 *       is performed. If the macro is defined as `STD_OFF`, the check is bypassed.
 *
 *       The function assumes that the `mac_mdio_read` function is used to read from the MII/MDIO
 *       register. The `ETH_CFG_CTRL_REG_BASE` macro or similar mechanism is used to obtain the
 *       base address of the controller's registers.
 *
 *       If the `RegValPtr` parameter is `NULL`, the function will report a parameter error using
 *       the `Det_ReportError` function (if error detection is enabled).
 *
 *       If the register read is successful, the `EthTrcv_ReadMiiIndication` function is called
 *       to indicate the read operation and provide the read value.
 */
/*PRQA S 1557 40*/
FUNC(Std_ReturnType, ETH_CODE) Eth_ReadMii
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint8, AUTOMATIC) TrcvIdx,
    VAR(uint8, AUTOMATIC) RegIdx,
    P2VAR(uint16, AUTOMATIC, ETH_APPL_CONST) RegValPtr
)
{
    Std_ReturnType RetVal = E_OK;
#if STD_OFF == MDIO_DET_CHECK_BYPASS
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_READMII);
#endif

    if (RetVal == E_OK) {
        if (NULL_PTR == RegValPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_READMII, ETH_E_PARAM_POINTER \
                                  );
#endif
            RetVal = E_NOT_OK;
        } else {
            sint32 ret = mac_mdio_read(ETH_CFG_CTRL_REG_BASE(CtrlIdx), \
                                       TrcvIdx, PHY_CLAUSE_22, RegIdx);

            if (ret < 0) {
                RetVal = E_NOT_OK;
            } else {
                *RegValPtr = (uint16)(ret & 0xFFFFu);
                EthTrcv_ReadMiiIndication(CtrlIdx, TrcvIdx, RegIdx, *RegValPtr);
            }
        }
    }

    return RetVal;
}
#endif

#if STD_ON == ETH_GET_COUNTVAL_API
/**
 * @brief Retrieves counter values from an Ethernet controller.
 *
 * This function retrieves various counter values from the specified Ethernet controller and stores
 * them in the provided buffer. The counter values can include statistics such as transmitted and
 * received frames, errors, etc.
 *
 * @param CtrlIdx The index of the Ethernet controller from which to retrieve counter values.
 * @param CounterPtr A pointer to a buffer where the retrieved counter values will be stored.
 *                   The buffer should be large enough to hold the `Eth_CounterType` structure.
 *
 * @return Returns `E_OK` if the counter values were successfully retrieved and stored in the
 *         provided buffer, or `E_NOT_OK` if an error occurred (e.g., invalid controller index,
 *         `NULL` pointer, or failed counter update).
 *
 * @note This function performs a validity check on the controller index using the `Eth_Det_Check`
 *       function. If the check fails, the function returns `E_NOT_OK`.
 *
 *       If the `CounterPtr` parameter is `NULL`, the function will report a parameter error using
 *       the `Det_ReportError` function (if error detection is enabled).
 *
 *       The function updates the MMC (Media Management Counter) status of the specified controller
 *       before retrieving the counter values. This ensures that the retrieved values are up-to-date.
 *
 *       The retrieved counter values are copied to the provided buffer using the `Mcal_MemCpy` function.
 *       The `Eth_gCounter` array is assumed to hold the counter values for each controller.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_GetCounterValues
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    P2VAR(Eth_CounterType, AUTOMATIC, ETH_APPL_CONST) CounterPtr
)
{
    Std_ReturnType RetVal = E_OK;
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETCOUNTERVALUES);

    if (RetVal == E_OK) {
        if (NULL_PTR == CounterPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETCOUNTERVALUES, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        } else {
            Eth_update_mmc_status(CtrlIdx);
            Mcal_MemCpy(CounterPtr, Eth_gCounter[CtrlIdx], sizeof(Eth_CounterType));
        }
    }

    return RetVal;
}
#endif


#if STD_ON == ETH_GET_RXSTATS_API
/**
 * @brief Retrieves receive statistics from an Ethernet controller.
 *
 * This function retrieves the receive statistics (e.g., received frames, errors, etc.) from the
 * specified Ethernet controller and stores them in the provided buffer.
 *
 * @param CtrlIdx The index of the Ethernet controller from which to retrieve receive statistics.
 * @param RxStats A pointer to a buffer where the retrieved receive statistics will be stored.
 *                The buffer should be large enough to hold the `Eth_RxStatsType` structure.
 *
 * @return Returns `E_OK` if the receive statistics were successfully retrieved and stored in the
 *         provided buffer, or `E_NOT_OK` if an error occurred (e.g., invalid controller index,
 *         `NULL` pointer, or failed statistics update).
 *
 * @note This function performs a validity check on the controller index using the `Eth_Det_Check`
 *       function. If the check fails, the function returns `E_NOT_OK`.
 *
 *       If the `RxStats` parameter is `NULL`, the function will report a parameter error using
 *       the `Det_ReportError` function (if error detection is enabled).
 *
 *       The function updates the MMC (Media Management Counter) status of the specified controller
 *       before retrieving the receive statistics. This ensures that the retrieved statistics are
 *       up-to-date.
 *
 *       The retrieved receive statistics are copied to the provided buffer using the `Mcal_MemCpy`
 *       function. The `Eth_gRxStats` array is assumed to hold the receive statistics for each
 *       controller.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_GetRxStats
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    P2VAR(Eth_RxStatsType, AUTOMATIC, ETH_APPL_CONST) RxStats
)
{
    Std_ReturnType RetVal = E_OK;
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETRXSTATS);

    if (RetVal == E_OK) {
        if (NULL_PTR == RxStats) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETRXSTATS, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        } else {
            Eth_update_mmc_status(CtrlIdx);
            Mcal_MemCpy(RxStats, Eth_gRxStats[CtrlIdx], sizeof(Eth_RxStatsType));
        }
    }

    return RetVal;
}
#endif /*ETH_GET_RXSTATS_API*/



#if STD_ON == ETH_GET_TXSTATS_API
/**
 * @brief Retrieves transmit statistics from an Ethernet controller.
 *
 * This function retrieves the transmit statistics (e.g., transmitted frames, errors, etc.) from
 * the specified Ethernet controller and stores them in the provided buffer.
 *
 * @param CtrlIdx The index of the Ethernet controller from which to retrieve transmit statistics.
 * @param TxStats A pointer to a buffer where the retrieved transmit statistics will be stored.
 *                The buffer should be large enough to hold the `Eth_TxStatsType` structure.
 *
 * @return Returns `E_OK` if the transmit statistics were successfully retrieved and stored in the
 *         provided buffer, or `E_NOT_OK` if an error occurred (e.g., invalid controller index,
 *         `NULL` pointer, or failed statistics update).
 *
 * @note This function performs a validity check on the controller index using the `Eth_Det_Check`
 *       function. If the check fails, the function returns `E_NOT_OK`.
 *
 *       If the `TxStats` parameter is `NULL`, the function will report a parameter error using
 *       the `Det_ReportError` function (if error detection is enabled).
 *
 *       The function updates the MMC (Media Management Counter) status of the specified controller
 *       before retrieving the transmit statistics. This ensures that the retrieved statistics are
 *       up-to-date.
 *
 *       The retrieved transmit statistics are copied to the provided buffer using the `Mcal_MemCpy`
 *       function. The `Eth_gTxStats` array is assumed to hold the transmit statistics for each
 *       controller.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_GetTxStats
(
    // Index of the control unit
    VAR(uint8, AUTOMATIC) CtrlIdx,
    // Pointer to the transmission statistics structure
    P2VAR(Eth_TxStatsType, AUTOMATIC, ETH_APPL_CONST) TxStats
)
{
    // Variable to store the return value
    Std_ReturnType RetVal = E_OK;
    // Check if the control unit is valid
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETTXSTATS);

    // If the control unit is valid
    if (RetVal == E_OK) {
        // If the pointer to the transmission statistics structure is NULL
        if (NULL_PTR == TxStats) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            // Report an error
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETTXSTATS, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            // Set the return value to E_NOT_OK
            RetVal = E_NOT_OK;
        } else {
            // Update the MMC status
            Eth_update_mmc_status(CtrlIdx);
            // Copy the transmission statistics to the structure
            Mcal_MemCpy(TxStats, Eth_gTxStats[CtrlIdx], sizeof(Eth_TxStatsType));
        }
    }

    // Return the return value
    return RetVal;
}
#endif /*ETH_GET_TXSTATS_API*/

#if STD_ON == ETH_GET_TXERRORCOUNT_API
/**
 * @brief Retrieves transmit error counter values from an Ethernet controller.
 *
 * This function retrieves the transmit error counter values (e.g., late collisions, excessive
 * collisions, etc.) from the specified Ethernet controller and stores them in the provided buffer.
 *
 * @param CtrlIdx The index of the Ethernet controller from which to retrieve transmit error
 *                counter values.
 * @param TxErrorPtr A pointer to a buffer where the retrieved transmit error counter values will
 *                   be stored. The buffer should be large enough to hold the
 *                   `Eth_TxErrorCounterValuesType` structure.
 *
 * @return Returns `E_OK` if the transmit error counter values were successfully retrieved and
 *         stored in the provided buffer, or `E_NOT_OK` if an error occurred (e.g., invalid
 *         controller index, `NULL` pointer, or failed counter update).
 *
 * @note This function performs a validity check on the controller index using the `Eth_Det_Check`
 *       function. If the check fails, the function returns `E_NOT_OK`.
 *
 *       If the `TxErrorPtr` parameter is `NULL`, the function will report a parameter error using
 *       the `Det_ReportError` function (if error detection is enabled).
 *
 *       The function updates the MMC (Media Management Counter) status of the specified controller
 *       before retrieving the transmit error counter values. This ensures that the retrieved values
 *       are up-to-date.
 *
 *       The retrieved transmit error counter values are copied to the provided buffer using the
 *       `Mcal_MemCpy` function. The `Eth_gTxErrorCounter` array is assumed to hold the transmit error
 *       counter values for each controller.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_GetTxErrorCounterValues
(
    // Control index
    VAR(uint8, AUTOMATIC) CtrlIdx,
    // Pointer to Tx error counter values
    P2VAR(Eth_TxErrorCounterValuesType, AUTOMATIC, ETH_APPL_CONST) TxErrorPtr
)
{
    // Return value
    Std_ReturnType RetVal = E_OK;
    // Check if the control index is valid
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETTXERRORCOUNTERVALUE);

    // If the control index is valid
    if (RetVal == E_OK) {
        // Check if the pointer is NULL
        if (NULL_PTR == TxErrorPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            // Report an error if the pointer is NULL
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETTXERRORCOUNTERVALUE, ETH_E_PARAM_POINTER \
                                  );
#endif
            // Set the return value to not OK
            RetVal = E_NOT_OK;
        } else {
            // Update the MMC status
            Eth_update_mmc_status(CtrlIdx);
            // Copy the Tx error counter values to the pointer
            Mcal_MemCpy(TxErrorPtr, Eth_gTxErrorCounter[CtrlIdx], sizeof(Eth_TxErrorCounterValuesType));
        }
    }

    // Return the return value
    return RetVal;
}
#endif /* ETH_GET_TXERRORCOUNT_API */

#if STD_ON == ETH_GET_GLOBALTIME_API
/**
 * @brief Retrieves the current time and time quality from an Ethernet controller.
 *
 * This function retrieves the current time (in seconds and nanoseconds) and the time quality
 * indicator from the specified Ethernet controller. The time quality indicator indicates the
 * validity and accuracy of the retrieved time.
 *
 * @param CtrlIdx The index of the Ethernet controller from which to retrieve the current time
 *                and time quality.
 * @param timeQualPtr A pointer to a variable where the time quality indicator will be stored.
 *                    The value should be one of the `Eth_TimeStampQualType` enumerations,
 *                    indicating the validity and accuracy of the retrieved time.
 * @param timeStampPtr A pointer to a buffer where the retrieved current time will be stored.
 *                     The buffer should be large enough to hold the `Eth_TimeStampType`
 *                     structure.
 *
 * @return Returns `E_OK` if the current time and time quality were successfully retrieved and
 *         stored in the provided buffers, or `E_NOT_OK` if an error occurred (e.g., invalid
 *         controller index, `NULL` pointer, or failed time retrieval).
 *
 * @note This function performs a validity check on the controller index using the `Eth_Det_Check`
 *       function. If the check fails, the function returns `E_NOT_OK`.
 *
 *       If either of the `timeStampPtr` or `timeQualPtr` parameters is `NULL`, the function will
 *       report a parameter error using the `Det_ReportError` function (if error detection is
 *       enabled).
 *
 *       The retrieved current time is stored in the `timeStampPtr` buffer using the
 *       `Eth_TimeStampType` structure. The `secondsHi` field is set to 0, as the function only
 *       retrieves the `seconds` and `nanoseconds` components of the time. The `dwmac_get_time`
 *       function is assumed to be used for retrieving the time from the specified controller.
 *
 *       The retrieved time quality indicator is stored in the `timeQualPtr` variable, indicating
 *       the validity and accuracy of the retrieved time. The `ETH_VALID` value is used to
 *       indicate that the retrieved time is valid.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_GetCurrentTime
(
    // Index of the Ethernet controller
    VAR(uint8, AUTOMATIC) CtrlIdx,
    // Pointer to the timestamp quality
    P2VAR(Eth_TimeStampQualType, AUTOMATIC, ETH_APPL_CONST) timeQualPtr,
    // Pointer to the timestamp
    P2VAR(Eth_TimeStampType, AUTOMATIC, ETH_APPL_CONST) timeStampPtr
)
{
    // Variable to store the return value
    Std_ReturnType RetVal = E_OK;
    // Check if the Ethernet controller is detected
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETCURRENTTIME);

    // If the Ethernet controller is detected
    if (RetVal == E_OK) {
        // If the timestamp pointer or the timestamp quality pointer is NULL
        if (NULL_PTR == timeStampPtr || NULL_PTR == timeQualPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            // Report an error
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETCURRENTTIME, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            // Set the return value to not OK
            RetVal = E_NOT_OK;
        } else {
            // Set the seconds high byte to 0
            timeStampPtr->secondsHi = 0;
            // Get the current time from the Ethernet controller
            dwmac_get_time(ETH_CFG_CTRL_REG_BASE(CtrlIdx),
                           &timeStampPtr->seconds, &timeStampPtr->nanoseconds);
            // Set the timestamp quality to valid
            *timeQualPtr = ETH_VALID;
        }
    }

    // Return the return value
    return RetVal;
}


/**
 * @brief Enables egress time stamping for a specific transmit buffer.
 *
 * This function enables egress (transmit) time stamping for the specified transmit buffer of
 * the given Ethernet controller. When enabled, the timestamp of the transmitted frame will be
 * captured and stored.
 *
 * @param CtrlIdx The index of the Ethernet controller for which to enable egress time stamping.
 * @param BufIdx The index of the transmit buffer for which to enable egress time stamping.
 *
 * @note This function performs two validity checks:
 *       - A check on the controller index using the `Eth_Det_Check` function.
 *       - A check on the transmit buffer index using the `Eth_Transmit_Det_Check` function.
 *       If either check fails, the function does not enable egress time stamping.
 *
 *       Before enabling egress time stamping, the function checks if the transmit buffer index
 *       is within the valid range for the specified controller. If the index is valid, the
 *       `TX_TS_EN_BIT` bit in the corresponding transmit timestamp register is set to enable
 *       time stamping for the buffer.
 *
 *       The lower 15 bits of the transmit timestamp register are assumed to be used to store
 *       the descriptor index, and the `TX_TS_EN_BIT` bit is assumed to be used to enable time
 *       stamping.
 */
FUNC(void, ETH_CODE) Eth_EnableEgressTimeStamp
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(Eth_BufIdxType, AUTOMATIC) BufIdx
)
{
    Std_ReturnType RetVal = E_OK;
    // Check if the control index is valid
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_ENABLEEGRESSTIMESTAMP);
    // Check if the buffer index is valid
    RetVal |= Eth_Transmit_Det_Check(CtrlIdx,BufIdx,ETH_SID_ENABLEEGRESSTIMESTAMP);
    // If both checks pass
    if (RetVal == E_OK) {
        // Check if the buffer index is within the range of the buffer count
        if (EthGetBufferCount(CtrlIdx, FALSE) >= BufIdx) {
            /* The lower 15bit is used to store desc idx*/
            Eth_gTxTimeStamp[CtrlIdx][BufIdx] |= TX_TS_EN_BIT;
        }
    }
}
/**
 * @brief Retrieves the egress (transmit) time stamp for a specific transmit buffer.
 *
 * This function retrieves the egress (transmit) time stamp for the specified transmit buffer
 * of the given Ethernet controller. The time stamp indicates the time when the frame was
 * transmitted on the network.
 *
 * @param CtrlIdx The index of the Ethernet controller from which to retrieve the egress time
 *                stamp.
 * @param BufIdx The index of the transmit buffer for which to retrieve the egress time stamp.
 * @param timeQualPtr A pointer to a variable where the time stamp quality indicator will be
 *                    stored. The value should be one of the `Eth_TimeStampQualType`
 *                    enumerations, indicating the validity of the retrieved time stamp.
 * @param timeStampPtr A pointer to a buffer where the retrieved egress time stamp will be
 *                     stored. The buffer should be large enough to hold the `Eth_TimeStampType`
 *                     structure.
 *
 * @note This function performs two validity checks:
 *       - A check on the controller index using the `Eth_Det_Check` function.
 *       - A check on the transmit buffer index using the `Eth_Transmit_Det_Check` function.
 *       If either check fails, the function does not retrieve the egress time stamp.
 *
 *       If either of the `timeQualPtr` or `timeStampPtr` parameters is `NULL`, the function will
 *       report a parameter error using the `Det_ReportError` function (if error detection is
 *       enabled).
 *
 *       The function retrieves the transmit descriptor for the specified buffer using the
 *       `form_bufidx_get_desc` function. It then checks the transmit timestamp status using the
 *       `dwmac_wrback_get_tx_timestamp_status` function. If the timestamp is available, the
 *       function copies the timestamp values (nanoseconds and seconds) from the descriptor to
 *       the `timeStampPtr` buffer and sets the `timeQualPtr` variable to `ETH_VALID`. If the
 *       timestamp is not available, the `timeQualPtr` variable is set to `ETH_INVALID`.
 *
 *       The `secondsHi` field of the `timeStampPtr` buffer is set to 0, as the function only
 *       retrieves the `seconds` and `nanoseconds` components of the timestamp.
 */
FUNC(void, ETH_CODE) Eth_GetEgressTimeStamp
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(Eth_BufIdxType, AUTOMATIC) BufIdx,
    P2VAR(Eth_TimeStampQualType, AUTOMATIC, ETH_APPL_CONST) timeQualPtr,
    P2VAR(Eth_TimeStampType, AUTOMATIC, ETH_APPL_CONST) timeStampPtr
)
{
    Std_ReturnType RetVal = E_OK;
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETEGRESSTIMESTAMP);
    RetVal |= Eth_Transmit_Det_Check(CtrlIdx,BufIdx,ETH_SID_GETEGRESSTIMESTAMP);
    if (RetVal == E_OK) {
        if ((NULL_PTR == timeQualPtr) || (NULL_PTR == timeStampPtr)) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETEGRESSTIMESTAMP, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
        } else {
            struct dma_desc *desc = form_bufidx_get_desc(CtrlIdx, BufIdx);

            if (dwmac_wrback_get_tx_timestamp_status(desc)) {
                timeStampPtr->nanoseconds = desc->des0;
                timeStampPtr->seconds = desc->des1 ;
                timeStampPtr->secondsHi = 0;
                *timeQualPtr =  ETH_VALID;
            } else {
                *timeQualPtr =  ETH_INVALID;
            }
        }
    }
}

/**
 * @brief Retrieves the ingress (receive) time stamp for a specific received frame.
 *
 * This function retrieves the ingress (receive) time stamp for a frame that has been received
 * by the specified Ethernet controller. The time stamp indicates the time when the frame was
 * received on the network.
 *
 * @param CtrlIdx The index of the Ethernet controller from which to retrieve the ingress time
 *                stamp.
 * @param DataPtr A pointer to the received frame data. This parameter is used to identify the
 *                buffer that contains the received frame.
 * @param timeQualPtr A pointer to a variable where the time stamp quality indicator will be
 *                    stored. The value should be one of the `Eth_TimeStampQualType`
 *                    enumerations, indicating the validity of the retrieved time stamp.
 * @param timeStampPtr A pointer to a buffer where the retrieved ingress time stamp will be
 *                     stored. The buffer should be large enough to hold the `Eth_TimeStampType`
 *                     structure.
 *
 * @note This function performs a validity check on the controller index using the
 *       `Eth_Det_Check` function. If the check fails, the function does not retrieve the
 *       ingress time stamp.
 *
 *       If any of the `timeQualPtr`, `timeStampPtr`, or `DataPtr` parameters is `NULL`, the
 *       function will report a parameter error using the `Det_ReportError` function (if error
 *       detection is enabled).
 *
 *       The function first determines the buffer index (`BufIdx`) of the received frame using
 *       the `DataPtr` parameter and the `EthBuffIdxFormAddr` function. It then retrieves the
 *       current and next DMA descriptors for the frame using the `get_dma_desc` and
 *       `get_dma_desc_next` functions, respectively.
 *
 *       The function checks if the current descriptor is a context descriptor and if the
 *       receive timestamp status is set using the `dwmac_wrback_get_rx_timestamp_status`
 *       function. If both conditions are true, the function copies the timestamp values
 *       (nanoseconds and seconds) from the next descriptor to the `timeStampPtr` buffer and
 *       sets the `timeQualPtr` variable to `ETH_VALID`. If either condition is false, the
 *       `timeQualPtr` variable is set to `ETH_INVALID`.
 *
 *       The `secondsHi` field of the `timeStampPtr` buffer is set to 0, as the function only
 *       retrieves the `seconds` and `nanoseconds` components of the timestamp.
 *
 *       If the buffer index is invalid (i.e., `ILLEGAL_BUFF_IDX`), the `timeQualPtr` variable
 *       is also set to `ETH_INVALID`.
 */
FUNC(void, ETH_CODE) Eth_GetIngressTimeStamp
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    P2CONST(Eth_DataType, AUTOMATIC, ETH_APPL_CONST) DataPtr, \
    P2VAR(Eth_TimeStampQualType, AUTOMATIC, ETH_APPL_CONST) timeQualPtr,
    P2VAR(Eth_TimeStampType, AUTOMATIC, ETH_APPL_CONST) timeStampPtr
)
{
    Eth_BufIdxType BufIdx;
    Std_ReturnType RetVal = E_OK;
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_GETINGRESSTIMESTAMP);

    if (RetVal == E_OK) {
        if ((NULL_PTR == timeQualPtr) || (NULL_PTR == timeStampPtr) || (NULL_PTR == DataPtr)) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_GETINGRESSTIMESTAMP, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
        } else {
            /* Get the idx of buf from it's addr */
            BufIdx = EthBuffIdxFormAddr(CtrlIdx, DataPtr, TRUE);

            if (ILLEGAL_BUFF_IDX != BufIdx ) {
                /* Get Current desc */
                struct dma_desc *cur_desc = get_dma_desc(CtrlIdx, MULTI_CH_RX_CH_IDX,
                                            Eth_gRxTimeStamp[CtrlIdx][BufIdx], TRUE);
                /* Get desc addr from idx of buf */
                struct dma_desc *next_desc = get_dma_desc_next(CtrlIdx, MULTI_CH_RX_CH_IDX,
                                             Eth_gRxTimeStamp[CtrlIdx][BufIdx], TRUE);

                /* This desc is a context desc */
                if (1u == dwmac_wrback_get_rx_timestamp_status(cur_desc, next_desc)) {
                    timeStampPtr->nanoseconds = next_desc->des0;
                    timeStampPtr->seconds = next_desc->des1 ;
                    timeStampPtr->secondsHi  = 0;
                    *timeQualPtr =  ETH_VALID;
                } else {
                    *timeQualPtr =  ETH_INVALID;
                }
            } else {
                *timeQualPtr =  ETH_INVALID;
            }
        }
    }
}
#endif /* ETH_GET_GLOBALTIME_API */

#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE_FAST
#include "Eth_MemMap.h"
/**
 * @brief Provides a transmit buffer for the specified Ethernet controller.
 *
 * This function allocates a transmit buffer for the specified Ethernet controller, taking
 * into account the requested priority and buffer length.
 *
 * @param CtrlIdx The index of the Ethernet controller for which to provide the transmit
 *                buffer.
 * @param Priority The priority level for the transmit buffer. Higher values indicate higher
 *                 priority.
 * @param BufIdxPtr A pointer to a variable where the allocated buffer index will be stored.
 * @param BufPtr A pointer to a pointer where the allocated buffer address will be stored.
 * @param LenBytePtr A pointer to a variable where the length of the data to be transmitted
 *                    (in bytes) will be provided. The function will adjust this value to
 *                    include the necessary space for the Ethernet frame header.
 *
 * @return A `BufReq_ReturnType` value indicating the status of the buffer request:
 *         - `BUFREQ_OK`: The buffer was successfully allocated.
 *         - `BUFREQ_E_NOT_OK`: The buffer request failed due to an invalid parameter or
 *           other error.
 *         - `BUFREQ_E_BUSY`: The buffer could not be allocated due to a lack of available
 *           buffers.
 *         - `BUFREQ_E_OVFL`: The buffer length exceeded the maximum allowed value.
 *
 * @note This function performs a validity check on the controller index using the
 *       `Eth_Det_Check` function. If the priority level is invalid (i.e., it is equal to or
 *       greater than `MAX_PRIORITY_LEVEL`), the function sets the return value to
 *       `BUFREQ_E_NOT_OK`.
 *
 *       If any of the `BufIdxPtr`, `LenBytePtr`, or `BufPtr` parameters is `NULL`, the
 *       function will report a parameter error using the `Det_ReportError` function (if
 *       error detection is enabled) and set the return value to `BUFREQ_E_NOT_OK`.
 *
 *       The function calculates the total length of the buffer, including the necessary
 *       space for the Ethernet frame header, by adding `MAC_HEADER_LEN` to the provided
 *       length in `LenBytePtr`. It then attempts to allocate a buffer of this length using
 *       the `EthBuffAlloc` function.
 *
 *       If the buffer allocation fails (due to lack of available buffers or buffer overflow),
 *       the function sets the return value to `BUFREQ_E_BUSY` or `BUFREQ_E_OVFL`,
 *       respectively. If the buffer is successfully allocated, the function updates the
 *       `BufIdxPtr` and `LenBytePtr` parameters with the allocated buffer index and adjusted
 *       length, respectively, and sets the return value to `BUFREQ_OK`.
 *
 *       If the Ethernet controller is configured with multiple DMA channels and traffic
 *       shaping is enabled, the function will set the transmit priority for the allocated
 *       buffer based on the provided priority level and the controller's configuration.
 */
FUNC(BufReq_ReturnType, ETH_CODE) Eth_ProvideTxBuffer
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint8, AUTOMATIC) Priority,
    P2VAR(Eth_BufIdxType, AUTOMATIC, ETH_APPL_CONST) BufIdxPtr,
    P2P2VAR(uint8, AUTOMATIC, ETH_APPL_CONST) BufPtr,
    P2VAR(uint16, AUTOMATIC, ETH_APPL_CONST) LenBytePtr
)
{
    Std_ReturnType ret = E_OK;
    VAR(sint32, AUTOMATIC) result;
    VAR(BufReq_ReturnType, AUTOMATIC) RetVal = BUFREQ_E_NOT_OK;
    /* reserve 14 bytes for ethnet fream header */
    VAR(uint16, AUTOMATIC) LenByte;

    // Check if the function is called with a valid control index
    ret = Eth_Det_Check(CtrlIdx, ETH_SID_PROVIDETXBUFFER);

    // Check if the priority is valid
    if (Priority >= MAX_PRIORITY_LEVEL) {
        ret = E_NOT_OK;
    }

    // If the control index and priority are valid
    if (ret == E_OK) {
#if (ETH_MAX_DMA_CHANNEL > 1U)
        // Get the control configuration for the given control index
        const Eth_CntrlConfigType *CntrlConfig = ETH_CFG_CTRL_PARM_PTR(CtrlIdx);
#endif
        // Check if the buffer index pointer, length byte pointer and buffer pointer are not NULL
        if (NULL_PTR == BufIdxPtr || NULL_PTR == LenBytePtr || NULL_PTR == BufPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            // Report an error if any of the pointers are NULL
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_PROVIDETXBUFFER, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = BUFREQ_E_NOT_OK;
        } else {
            // Add the MAC header length to the length byte pointer
            LenByte = *LenBytePtr + MAC_HEADER_LEN;
            // Allocate a buffer with the given length byte
            result = EthBuffAlloc(CtrlIdx, &LenByte, BufPtr, BufIdxPtr, FALSE);

            // If the buffer allocation fails
            if (-1 == result) {
                RetVal = BUFREQ_E_BUSY;
            // If the buffer allocation is successful but the length byte is overflowed
            } else if (result == -2) {
                *LenBytePtr = LenByte;
                RetVal = BUFREQ_E_OVFL;
            // If the buffer allocation is successful and the length byte is not overflowed
            } else {
                *LenBytePtr = LenByte;
                RetVal = BUFREQ_OK;
#if (ETH_MAX_DMA_CHANNEL > 1U)
                /* direct forward will occupy one channel */
                int usableCh = ETH_MAX_DMA_CHANNEL;
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
                if (TRUE == ETH_CFG_CTRL_TXQ_DRCT_ENABLE(CtrlIdx))
                {
                    usableCh = ETH_MAX_DMA_CHANNEL - 1;
                }
#endif

                // If the traffic shaper is set to AVB and the transmission traffic algorithm is set to SP
                if (CntrlConfig->TrafficShaper == MTL_QUEUE_MODE_AVB &&
                    CntrlConfig->TxTrafficAlgorithms == MTL_TX_ALGORITHM_SP) {
                    // Set the transmission priority for the given buffer index
                    Eth_gTxPriorty[CtrlIdx][*BufIdxPtr] =
                        (Priority >= usableCh) ? usableCh - 1 : Priority;
                } else {
                    // default use queue 0 for all pac.
                    Eth_gTxPriorty[CtrlIdx][*BufIdxPtr] = 0;

                    // search config to select queue .
                    for (uint8 u8ChannelCount = 0; u8ChannelCount < usableCh; u8ChannelCount++) {
                        // If the priority is within the range of the current channel
                        if (CntrlConfig->CbsCfg[u8ChannelCount].PriortyMin <= Priority && \
                            Priority <= CntrlConfig->CbsCfg[u8ChannelCount].PriortyMax) {
                            // Set the transmission priority for the given buffer index
                            Eth_gTxPriorty[CtrlIdx][*BufIdxPtr] = u8ChannelCount;
                            break;
                        }
                    }
                }

#endif
            }
        }
    }

    // Return the return value
    return RetVal;
}
/**
 * @brief Transmits an Ethernet frame using the specified controller and buffer.
 *
 * This function prepares and transmits an Ethernet frame using the specified controller
 * and buffer. It handles various error checks and configurations based on the provided
 * parameters and the controller's configuration.
 *
 * @param CtrlIdx The index of the Ethernet controller to use for transmission.
 * @param BufIdx The index of the buffer containing the frame data to transmit.
 * @param FrameType The type of the Ethernet frame to transmit.
 * @param TxConfirmation A flag indicating whether a transmit confirmation is required.
 * @param LenByte The length of the frame data, in bytes, excluding the Ethernet header.
 * @param PhysAddrPtr A pointer to the physical address (MAC address) to use in the frame.
 *
 * @return A `Std_ReturnType` value indicating the status of the transmission:
 *         - `E_OK`: The frame was successfully transmitted.
 *         - `E_NOT_OK`: The transmission failed due to an error.
 *
 * @note This function performs several checks before attempting to transmit the frame:
 *       - It verifies that the controller index is valid using `Eth_Det_Check`.
 *       - It checks that the buffer index is valid and the buffer is allocated using
 *         `Eth_Transmit_Det_Check`.
 *       - It ensures that the physical address pointer is not `NULL` and that the
 *         controller is in active mode.
 *       - It verifies that the buffer size is sufficient to hold the frame data and
 *         Ethernet header.
 *
 *       If any of these checks fail, the function reports an error using `Det_ReportError`
 *       (if error detection is enabled) and returns `E_NOT_OK`.
 *
 *       If the controller is configured with multiple DMA channels, the function will
 *       select the appropriate channel based on the transmit priority associated with
 *       the buffer.
 *
 *       The function prepares the DMA descriptor for the frame, including the physical
 *       address of the buffer, the frame length, and various flags indicating the
 *       transmission options. It then attempts to allocate the descriptor using
 *       `Eth_AllocDesc`.
 *
 *       If the descriptor allocation fails, the function returns `E_NOT_OK`. Otherwise,
 *       it adds the descriptor to the transmit queue using `locked_desc_put` and updates
 *       the transmit tail pointer to initiate the transmission.
 *
 *       If transmit confirmation is requested, the function sets the appropriate flag
 *       in the locked descriptor to enable confirmation.
 *
 *       If the controller is configured to use cacheable memory, the function flushes
 *       the relevant cache lines to ensure that the DMA has access to the latest data.
 *
 *       Finally, the function exits the critical section and returns the result of the
 *       transmission.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_Transmit(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(Eth_BufIdxType, AUTOMATIC) BufIdx,
    VAR(Eth_FrameType, AUTOMATIC) FrameType,
    VAR(boolean, AUTOMATIC) TxConfirmation,
    VAR(uint16, AUTOMATIC) LenByte,
    P2CONST(uint8, AUTOMATIC, ETH_APPL_CONST) PhysAddrPtr
)
{

    VAR(uint8,AUTOMATIC) chan_idx = 0;
    VAR(uint16, AUTOMATIC) len = 0;
    VAR(Std_ReturnType,AUTOMATIC) RetVal = E_OK;
    VAR(locked_desc_t, AUTOMATIC) fream;
    P2VAR(struct dma_desc, AUTOMATIC, AUTOMATIC) tdesc;
    P2VAR(uint8, AUTOMATIC, AUTOMATIC) Mem_BeforData;
    VAR(uint32, AUTOMATIC) flags =   DESC_FLAGS_TX_FIRST | \
                                     DESC_FLAGS_TX_LAST | \
                                     DESC_FLAGS_TX_CPC_CRC_PAD_INSER | \
                                     DESC_FLAGS_TX_SAIC_REPLA | \
                                     DESC_FLAGS_TX_OWN;
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_TRANSMIT);

    RetVal |= Eth_Transmit_Det_Check(CtrlIdx,BufIdx,ETH_SID_TRANSMIT);

    if (RetVal == E_OK) {
        if (NULL_PTR == PhysAddrPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (uint8) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (uint8) \
                                    ETH_SID_TRANSMIT, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        }else if (ETH_MODE_ACTIVE != ETH_CTRL_MODE(CtrlIdx)) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (uint8) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (uint8) \
                                    ETH_SID_TRANSMIT, ETH_E_INV_MODE \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        }else if (TRUE != EthBuffIsAllocated(CtrlIdx,BufIdx, FALSE)){
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (uint8) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (uint8) \
                                    ETH_SID_TRANSMIT, ETH_E_INV_PARAM \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        }else if (EthBuffGetSizeByIdx(CtrlIdx,BufIdx,FALSE) < (LenByte+MAC_HEADER_LEN)){
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (uint8) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (uint8) \
                                    ETH_SID_TRANSMIT, ETH_E_INV_PARAM \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        }
    }
    if (RetVal == E_OK) {
#if (ETH_MAX_DMA_CHANNEL > 1U)
                /* direct forward will occupy one channel */
                int usableCh = ETH_MAX_DMA_CHANNEL;
#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
                if (TRUE == ETH_CFG_CTRL_TXQ_DRCT_ENABLE(CtrlIdx))
                {
                    usableCh = ETH_MAX_DMA_CHANNEL - 1;
                }
#endif
        /* if chan_idx is ilegal to the default 0 channel */
        if(Eth_gTxPriorty[CtrlIdx][BufIdx] < usableCh){
            chan_idx = Eth_gTxPriorty[CtrlIdx][BufIdx];
        }
#endif
        /* interrupt */
        if (ETH_CFG_CTRL_TX_INT_MODE(CtrlIdx)) {
            flags |= DESC_FLAGS_IC;
        }

        Mem_BeforData = (P2VAR(uint8, AUTOMATIC, AUTOMATIC))\
                        EthBuffAddr(CtrlIdx, BufIdx, FALSE);

        /* full dts mac addr*/
        for (len = 0; len < 6u; len++) {
            Mem_BeforData[len] = PhysAddrPtr[len];
        }
        /* fream type */
        Mem_BeforData[12u] = (uint8)((FrameType >> 8u) & 0xFFu);
        Mem_BeforData[13u] = (uint8)(FrameType & 0xFFu);
        /*
            Critical protection here is to avoid interruption and interruption of the sending process.
        */
        SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_01();
#if STD_ON == ETH_GET_GLOBALTIME_API

        /* timeStamp support for tx */
        if (Eth_gTxTimeStamp[CtrlIdx][BufIdx] & TX_TS_EN_BIT) {
            flags |= DESC_FLAGS_TIMESTAMP;
            Eth_gTxTimeStamp[CtrlIdx][BufIdx] &= (uint32)(~TX_TS_EN_BIT);
        }

#endif
        // Allocate a descriptor for the Ethernet frame
        tdesc = Eth_AllocDesc(CtrlIdx, chan_idx, FALSE, \
                              LenByte + (uint16)MAC_HEADER_LEN, \
                              (uint32)Mem_BeforData, \
                              flags);

        // If the descriptor is NULL, return E_NOT_OK
        if ( tdesc == NULL_PTR ) {
            RetVal = E_NOT_OK;
        }

        // If the descriptor is allocated successfully
        if (RetVal == E_OK) {
            // Set the descriptor and buffer index
            fream.desc = (VAR(uint32, AUTOMATIC))tdesc;
            fream.buf_idx = BufIdx;
            fream.confirm = LOCKED_DESC_TX_DMA;

            // If TxConfirmation is TRUE, set the TxConfirmation flag
            if (TxConfirmation) {
                fream.confirm |= LOCKED_DESC_TX_CONFIRM;
            }

            // If the descriptor is not put successfully, free the descriptor and return E_NOT_OK
            if (locked_desc_put(CtrlIdx, chan_idx, &fream, FALSE)) {
                free_dma_desc(CtrlIdx, chan_idx, FALSE);
                RetVal = E_NOT_OK;
            }
        }

#if STD_ON == ETH_GET_GLOBALTIME_API
        Eth_gTxTimeStamp[CtrlIdx][BufIdx] = TX_DESC_IDX(GET_TX_DESC_INDEX(CtrlIdx, chan_idx, tdesc));
#endif
#if (ETH_MAX_DMA_CHANNEL > 1U)
        Eth_gTxTimeStamp[CtrlIdx][BufIdx] &= ~TX_DESC_CH_MASK;
        Eth_gTxTimeStamp[CtrlIdx][BufIdx] |= TX_DESC_CH_GEN(chan_idx);
#endif

        if (RetVal == E_OK) {
#if (ETH_NO_CACHEABLE_NEEDED == STD_OFF)
            /*PRQA S 0326 3*/
            Mcal_FlushCache((uint32)tdesc, ROUNDUP(sizeof(*tdesc), CACHE_LINE));
            Mcal_FlushCache((uint32)Mem_BeforData, ROUNDUP(LenByte + MAC_HEADER_LEN, CACHE_LINE));
#endif
            dwmac_set_tx_tail_ptr(ETH_CFG_CTRL_REG_BASE(CtrlIdx),
                                  soc_to_dma_address((uint32)&Eth_Desc_Buf[CtrlIdx][chan_idx][DESC_TX].desc[MAX_ETH_RING_LENTH]),
                                  chan_idx);
        }

        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_01();

    }

    return RetVal;
}
#define ETH_STOP_SEC_CODE_FAST
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE
#include "Eth_MemMap.h"
/**
 * @brief Handles the reception of Ethernet frames for the specified controller.
 *
 * This function is responsible for initiating the reception of Ethernet frames for the
 * specified controller. It performs various checks to ensure that the operation can be
 * performed safely and then calls the appropriate function to handle the reception.
 *
 * @param CtrlIdx The index of the Ethernet controller for which to receive frames.
 * @param FifoIdx A parameter that is currently not used by this function.
 * @param RxStatusPtr A pointer to a variable where the reception status will be stored.
 *
 * @return None.
 *
 * @note This function first checks the validity of the controller index using
 *       `Eth_Det_Check`. If the controller is not in active mode, it reports an error
 *       using `Det_ReportError` (if error detection is enabled) and does not proceed
 *       with the reception.
 *
 *       If the `RxStatusPtr` parameter is `NULL`, the function also reports an error and
 *       does not proceed.
 *
 *       If the controller is configured to use interrupts for reception, this function
 *       does not perform any further action, as the reception will be handled by the
 *       interrupt service routine.
 *
 *       If the controller is configured to use polling for reception, the function calls
 *       `rx_indication` to check for received frames and updates the `RxStatusPtr`
 *       parameter with the reception status.
 *
 *       Note that the `FifoIdx` parameter is currently not used by this function and is
 *       included for future compatibility or extension.
 */
FUNC(void, ETH_CODE) Eth_Receive
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint8, AUTOMATIC) FifoIdx,
    P2VAR(Eth_RxStatusType, AUTOMATIC, ETH_APPL_CONST) RxStatusPtr
)
{
    (void)FifoIdx;
    Std_ReturnType RetVal = E_OK;
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_RECEIVE);

    if (RetVal == E_OK) {
        if (NULL_PTR == RxStatusPtr) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (uint8) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (uint8) \
                                    ETH_SID_RECEIVE, ETH_E_PARAM_POINTER \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        }else if (ETH_MODE_ACTIVE != ETH_CTRL_MODE(CtrlIdx)) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (uint8) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (uint8) \
                                    ETH_SID_RECEIVE, ETH_E_INV_MODE \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        }
    }

    if (RetVal == E_OK) {
        if (ETH_CFG_CTRL_RX_INT_MODE(CtrlIdx) == FALSE) {
            *RxStatusPtr = (Eth_RxStatusType)rx_indication(CtrlIdx, 0);
        }
    }
}
/**
 * @brief Handles transmit confirmations for the specified Ethernet controller.
 *
 * This function is responsible for processing transmit confirmations for the specified
 * Ethernet controller. It checks the controller's status and, if appropriate, initiates
 * the processing of transmit confirmation indications.
 *
 * @param CtrlIdx The index of the Ethernet controller for which to handle transmit confirmations.
 *
 * @return None.
 *
 * @note This function first checks the validity of the controller index using
 *       `Eth_Det_Check`. If the controller is not in active mode, it reports an error
 *       using `Det_ReportError` (if error detection is enabled) and does not proceed
 *       with the transmit confirmation handling.
 *
 *       If the controller is configured to use interrupts for transmit confirmation,
 *       this function does not perform any further action, as the transmit confirmation
 *       will be handled by the interrupt service routine.
 *
 *       If the controller is configured to use polling for transmit confirmation, the
 *       function iterates over all DMA channels in reverse order and calls
 *       `tx_indication` for each channel to check for transmit completions.
 *
 *       Note that the iteration over DMA channels in reverse order is done to optimize
 *       for the typical case where new transmit requests are added to the end of the
 *       transmit queue, ensuring that recently submitted frames are checked first.
 */
FUNC(void, ETH_CODE) Eth_TxConfirmation
(
    VAR(uint8, AUTOMATIC) CtrlIdx
)
{
    Std_ReturnType RetVal = E_OK;
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_TXCONFIRMATION);

    if (RetVal == E_OK) {
        if (ETH_MODE_ACTIVE != ETH_CTRL_MODE(CtrlIdx)) {
#if STD_ON == ETH_DEV_ERROR_DETECT
            (void)Det_ReportError ( \
                                    (uint8) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (uint8) \
                                    ETH_SID_TXCONFIRMATION, ETH_E_INV_MODE \
                                  );
#endif /* ETH_DEV_ERROR_DETECT  */
            RetVal = E_NOT_OK;
        }
    }

    if (RetVal == E_OK) {
        if ((VAR(boolean, AUTOMATIC))FALSE == ETH_CFG_CTRL_TX_INT_MODE(CtrlIdx)) {
            /*PRQA S 2877 2*/
            for (sint8 channel = ETH_MAX_DMA_CHANNEL - 1; channel >= 0; channel--) {
                tx_indication(CtrlIdx, (uint8)channel, FALSE);
            }
        }/*ETH_CFG_ENABLETXINTERRUPT*/
    }
}

#if STD_ON == ETH_GET_VERSION_INFO_API
/**
 * @brief Retrieves version information for the Ethernet driver.
 *
 * This function provides version information about the Ethernet driver, including the
 * module ID, vendor ID, and software version numbers.
 *
 * @param VersionInfoPtr A pointer to a `Std_VersionInfoType` structure where the version
 *                       information will be stored.
 *
 * @return None.
 *
 * @note If error detection is enabled (`ETH_DEV_ERROR_DETECT` is set to `STD_ON`), this
 *       function checks if the `VersionInfoPtr` parameter is `NULL`. If it is, the
 *       function reports an error using `Det_ReportError` and does not proceed with
 *       filling the version information.
 *
 *       Otherwise, the function populates the `VersionInfoPtr` structure with the
 *       following information:
 *       - `moduleID`: The unique identifier of the Ethernet driver module.
 *       - `vendorID`: The vendor ID associated with the driver.
 *       - `sw_major_version`, `sw_minor_version`, `sw_patch_version`: The major, minor,
 *         and patch version numbers of the driver software.
 *
 *       The version information is retrieved from preprocessor definitions defined in
 *       the driver's header files.
 */
FUNC(void, ETH_CODE) Eth_GetVersionInfo
(
    P2VAR(Std_VersionInfoType, AUTOMATIC, ETH_APPL_CONST) VersionInfoPtr
)
{
#if STD_ON == ETH_DEV_ERROR_DETECT

    if (NULL_PTR == VersionInfoPtr) {
        (void)Det_ReportError ( \
                                (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) ETH_SID_GETVERSIONINFO, ETH_E_PARAM_POINTER \
                              );
    } else {
#endif /* ETH_DEV_ERROR_DETECT */
        VersionInfoPtr->moduleID = (VAR(uint16, AUTOMATIC))ETH_MODULE_ID;
        VersionInfoPtr->vendorID = (VAR(uint16, AUTOMATIC))ETH_C_VENDOR_ID;
        VersionInfoPtr->sw_major_version = (VAR(uint8, AUTOMATIC))ETH_C_SW_MAJOR_VERSION;
        VersionInfoPtr->sw_minor_version = (VAR(uint8, AUTOMATIC))ETH_C_SW_MINOR_VERSION;
        VersionInfoPtr->sw_patch_version = (VAR(uint8, AUTOMATIC))ETH_C_SW_PATCH_VERSION;

#if STD_ON == ETH_DEV_ERROR_DETECT
    }

#endif /* ETH_DEV_ERROR_DETECT */
}
#endif

FUNC(void, ETH_CODE) Eth_MainFunction(VAR(void, AUTOMATIC))
{
    ;
}

/*
    The interface defined by autosar can only describe the phy of Clause22.
    Clause45 phy Write
*/
/**
 * @brief Writes data to a PHY register using MDIO.
 *
 * This function writes data to a specified PHY register through the Management Data
 * Input/Output (MDIO) interface. It is used to configure the PHY device connected to
 * the Ethernet controller.
 *
 * @param CtrlIdx The index of the Ethernet controller to which the PHY is connected.
 * @param TrcvIdx The transceiver index, used to select the MDIO channel if multiple
 *                transceivers are supported.
 * @param Device The PHY device address on the MDIO bus.
 * @param PhyReg The register address within the PHY device to which to write data.
 * @param data The data to write to the PHY register.
 *
 * @return Std_ReturnType indicating the success or failure of the operation.
 *         - E_OK: The data was successfully written to the PHY register.
 *         - E_NOT_OK: The data could not be written to the PHY register.
 *
 * @note If MDIO detection check bypass is disabled (`MDIO_DET_CHECK_BYPASS` is set to
 *       `STD_OFF`), the function first checks the validity of the controller index
 *       using `Eth_Det_Check`. If the check fails, the function returns `E_NOT_OK`
 *       without attempting to write to the PHY register.
 *
 *       The actual write operation is performed by calling `mac_mdio_write`, which is
 *       a lower-level function that handles the MDIO communication protocol. If
 *       `mac_mdio_write` returns a non-zero value, indicating an error, the function
 *       returns `E_NOT_OK`.
 */
FUNC(Std_ReturnType, ETH_CODE) Eth_Mdio_Write
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint8, AUTOMATIC) TrcvIdx,
    VAR(uint8, AUTOMATIC) Device,
    VAR(uint16, AUTOMATIC) PhyReg,
    VAR(uint16, AUTOMATIC) data
)
{
    Std_ReturnType RetVal = E_OK;
#if STD_OFF == MDIO_DET_CHECK_BYPASS
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_WRITEMII_45);
#endif

    if (RetVal == E_OK) {
        if (mac_mdio_write(ETH_CFG_CTRL_REG_BASE(CtrlIdx), TrcvIdx, Device, PhyReg, data)) {
            RetVal = E_NOT_OK;
        }

    }

    return RetVal;
}
/*
    The interface defined by autosar can only describe the phy of Clause22.
    clause45 phy Read
*/
/**
 * @brief Reads data from a PHY register using MDIO.
 *
 * This function reads data from a specified PHY register through the Management Data
 * Input/Output (MDIO) interface. It is used to retrieve configuration or status
 * information from the PHY device connected to the Ethernet controller.
 *
 * @param CtrlIdx The index of the Ethernet controller to which the PHY is connected.
 * @param TrcvIdx The transceiver index, used to select the MDIO channel if multiple
 *                transceivers are supported.
 * @param Device The PHY device address on the MDIO bus.
 * @param PhyReg The register address within the PHY device from which to read data.
 * @param RegValPtr A pointer to a variable where the read data will be stored.
 *
 * @return Std_ReturnType indicating the success or failure of the operation.
 *         - E_OK: The data was successfully read from the PHY register and stored in
 *                 `RegValPtr`.
 *         - E_NOT_OK: The data could not be read from the PHY register, either because
 *                     `RegValPtr` was `NULL` or because an error occurred during the
 *                     MDIO read operation.
 *
 * @note If MDIO detection check bypass is disabled (`MDIO_DET_CHECK_BYPASS` is set to
 *       `STD_OFF`), the function first checks the validity of the controller index
 *       using `Eth_Det_Check`. If the check fails, the function returns `E_NOT_OK`
 *       without attempting to read from the PHY register.
 *
 *       The function also checks if `RegValPtr` is `NULL`. If it is, the function
 *       reports an error using `Det_ReportError` (if error detection is enabled) and
 *       returns `E_NOT_OK`.
 *
 *       The actual read operation is performed by calling `mac_mdio_read`, which is
 *       a lower-level function that handles the MDIO communication protocol. If
 *       `mac_mdio_read` returns a negative value, indicating an error, the function
 *       returns `E_NOT_OK`. Otherwise, the read data (masked to 16 bits) is stored in
 *       the variable pointed to by `RegValPtr`.
 */
FUNC(uint16, ETH_CODE) Eth_Mdio_Read
(
    VAR(uint8, AUTOMATIC) CtrlIdx,
    VAR(uint8, AUTOMATIC) TrcvIdx,
    VAR(uint8, AUTOMATIC) Device,
    VAR(uint16, AUTOMATIC) PhyReg,
    P2VAR(uint16, AUTOMATIC, ETH_APPL_CONST) RegValPtr
)
{
    // Declare a variable to store the data
    sint32 data = 0;
    // Declare a variable to store the return value
    Std_ReturnType RetVal = E_OK;
    // Check if MDIO_DET_CHECK_BYPASS is off
#if STD_OFF == MDIO_DET_CHECK_BYPASS
    // Call the Eth_Det_Check function
    RetVal = Eth_Det_Check(CtrlIdx, ETH_SID_READMII_45);
#endif
     // Check if the RegValPtr is NULL
     if (NULL_PTR == RegValPtr) {
        // Check if ETH_DEV_ERROR_DETECT is on
#if STD_ON == ETH_DEV_ERROR_DETECT
            // Call the Det_ReportError function
            (void)Det_ReportError ( \
                                    (VAR(uint8, AUTOMATIC)) ETH_MODULE_ID, \
                                    ETH_DRIVER_INSTANCE, (VAR(uint8, AUTOMATIC)) \
                                    ETH_SID_READMII_45, ETH_E_PARAM_POINTER \
                                  );
#endif
            // Set the return value to E_NOT_OK
            RetVal = E_NOT_OK;
    }
    // Check if the return value is OK
    if (RetVal == E_OK) {
        // Call the mac_mdio_read function
        data = mac_mdio_read(ETH_CFG_CTRL_REG_BASE(CtrlIdx), TrcvIdx, Device, PhyReg);

        // Check if the data is less than 0
        if (data < 0) {
            // Set the return value to E_NOT_OK
            RetVal = E_NOT_OK;
        } else {
            // Store the data in the RegValPtr
            *RegValPtr = (uint16)(data & 0xFFFFu);
        }
    }

    // Return the return value
    return RetVal;
}

#if defined(LOWPOWER_SUPPORT_SUSPEND_RESUME)
/**
 * @brief Suspends all Ethernet controllers associated with the specified core.
 *
 * This function iterates over all Ethernet controllers configured for the specified
 * core and suspends them by saving their current mode and state, and setting their
 * mode to `ETH_MODE_DOWN`. The function is intended to be used when the system needs
 * to temporarily stop all network activity associated with the core.
 *
 * @param CfgPtr A pointer to an `Eth_ConfigType` structure containing the configuration
 *               information for the Ethernet driver.
 *
 * @return Std_ReturnType indicating the success or failure of the operation.
 *         - E_OK: All controllers were successfully suspended.
 *         - A bitwise OR of E_NOT_OK values if any controllers could not be suspended
 *           (e.g., if they were not in the `ETH_STATE_INIT` state).
 *
 * @note This function first determines the core ID using `Eth_GetCoreID` and retrieves
 *       the core-specific configuration from the `CfgPtr` parameter. It then iterates
 *       over all controllers configured for the core, saving their current mode and
 *       state, and setting their mode to `ETH_MODE_DOWN` if they are in the
 *       `ETH_STATE_INIT` state.
 *
 *       The `Eth_gCtrl` global array is used to access the controller-specific
 *       configuration and state information. The `Eth_SaveMode` and `Eth_SaveState`
 *       fields in the controller's configuration structure are used to store the
 *       saved mode and state, respectively.
 *
 *       Note that only controllers in the `ETH_STATE_INIT` state are set to
 *       `ETH_MODE_DOWN`. Controllers in other states (e.g., `ETH_STATE_STARTED` or
 *       `ETH_STATE_STOPPED`) are left in their current mode and state.
 */
Std_ReturnType Eth_Suspend(const Eth_ConfigType* CfgPtr)
{
    // Get the core ID
    uint8 CoreId = Eth_GetCoreID();
    // Initialize the return value to E_OK
    Std_ReturnType Retval= E_OK;
    // Initialize the core control index to 0
    uint8   CoreCntrlIdx = 0U;
    // Get the core configuration
    const Eth_CoreConfigType* CoreConfig = CfgPtr->EthCoreConfig[CoreId];

    // Check if the core configuration is not NULL
    if(NULL_PTR != CoreConfig){
        // Loop through the maximum number of controllers
        for (CoreCntrlIdx = 0;CoreCntrlIdx <
                CoreConfig->EthMaxControllers; CoreCntrlIdx++){
            /* Save suspend mode */
            Eth_gCtrl[CoreCntrlIdx]->Eth_SaveMode = ETH_CTRL_MODE(CoreCntrlIdx);
            Eth_gCtrl[CoreCntrlIdx]->Eth_SaveState = ETH_CTRL_STATE(CoreCntrlIdx);
            // If the controller state is INIT, set the controller mode to DOWN
            if(ETH_STATE_INIT == ETH_CTRL_STATE(CoreCntrlIdx))
                Retval |= Eth_SetControllerMode(CoreCntrlIdx, ETH_MODE_DOWN);
        }
    }
    // Return the return value
    return Retval;
}
/**
 * @brief Resumes the operation of suspended Ethernet controllers.
 *
 * This function iterates through all Ethernet controllers associated with the current
 * core and attempts to resume their operation if they were previously suspended.
 * Specifically, it checks if the controller's saved state is `ETH_STATE_INIT` and, if
 * so, reinitializes the controller using `Eth_Init` and sets its mode to `ETH_MODE_ACTIVE`
 * if that was its saved mode.
 *
 * @param CfgPtr A pointer to an `Eth_ConfigType` structure containing the configuration
 *               information for the Ethernet driver.
 *
 * @return Std_ReturnType indicating the success or failure of the operation.
 *         - E_OK: All controllers were successfully resumed, or no controllers were
 *                 found in the saved state.
 *         - A bitwise OR of E_NOT_OK values if any controllers could not be resumed
 *           successfully (e.g., due to an error in `Eth_Init` or `Eth_SetControllerMode`).
 *
 * @note This function assumes that the controllers' saved states and modes were
 *       previously set by `Eth_Suspend` or similar functionality. It also assumes that
 *       `Eth_Init` and `Eth_SetControllerMode` are capable of reinitializing and
 *       setting the controller's mode, respectively, without causing conflicts or
 *       unexpected behavior.
 *
 *       It's important to note that calling `Eth_Resume` without a prior call to
 *       `Eth_Suspend` or similar functionality that sets the controllers' saved states
 *       and modes may result in undefined behavior.
 */
Std_ReturnType Eth_Resume(const Eth_ConfigType* CfgPtr)
{
    // Get the core ID
    uint8 CoreId = Eth_GetCoreID();
    // Initialize the return value
    Std_ReturnType Retval= E_OK;
    // Initialize the core control index
    uint8  CoreCntrlIdx = 0U;
    // Get the core configuration
    const Eth_CoreConfigType* CoreConfig = CfgPtr->EthCoreConfig[CoreId];

    // Check if the core configuration is not NULL
    if(NULL_PTR != CoreConfig){

        // Loop through the core controllers
        for (CoreCntrlIdx = 0;CoreCntrlIdx <
            CoreConfig->EthMaxControllers; CoreCntrlIdx++){
            // Check if the core controller is in the init state
            if(ETH_STATE_INIT == Eth_gCtrl[CoreCntrlIdx]->Eth_SaveState){
                // Initialize the core
                Eth_Init(CfgPtr);
                // Check if the core controller is in the active mode
                if(ETH_MODE_ACTIVE == Eth_gCtrl[CoreCntrlIdx]->Eth_SaveMode){
                    // Set the core controller to the active mode
                    Retval |= Eth_SetControllerMode(CoreCntrlIdx, ETH_MODE_ACTIVE);
                }
            }
        }
    }
    // Return the return value
    return Retval;
}
#endif

#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"

#ifdef __cplusplus
}
#endif
